보안 모델
무엇을 지키고, 무엇을 지키지 못하는지
이 페이지는 보안 기능을 자랑하는 소개가 아니라 위협 모델입니다. 무엇을 막고, 무엇이 남는 위험인지 그대로 적었습니다. 확인하지 않은 보장은 쓰지 않았습니다.
한눈에
서버
없음 — 키를 받는 백엔드가 없습니다
API 키
선택적 암호화(AES-256-GCM) + 자동 잠금
대화 기록
로컬(IndexedDB) · 선택적 암호화
서드파티 스크립트
AdSense — 콘텐츠 페이지에만
지키는 것
실제로 동작하는 보호만 적었습니다
아래 항목은 모두 이 저장소의 코드와 배포 설정에 들어 있습니다. 설정 방법까지 함께 적었습니다.
키 암호화 + 자동 잠금
암호구를 설정하면 API 키는 PBKDF2-SHA256(600,000회) → AES-256-GCM으로 암호화됩니다. 암호문은
keychat.apiKeys.v2에 저장되고, 평문 키는 잠금 해제 중에만 메모리에 있습니다. 같은 암호구로 대화 기록까지 암호화할 수 있고, 잠그면 복호화된 대화도 메모리에서 지워집니다. 자동 잠금은 5/15/30/60분·탭 전환 시·사용 안 함 중에서 고르고, 사이드바와 보안 탭에서 즉시 잠글 수도 있습니다.서버도 계정도 없습니다
이 사이트에는 키를 받는 서버가 없습니다. 회원가입도 로그인도, 서버 측 대화 로그도, 사용자 데이터베이스도 없습니다. KeyChat을 해킹해도 서버에서 가져갈 키가 없습니다. 있는 것은 정적 파일과 광고 슬롯뿐입니다.
브라우저에서 제공자로 직접
모든 요청은 이 브라우저에서 제공자 API로 직접 전송됩니다. Gemini 키도 URL이 아니라
x-goog-api-key헤더로 보냅니다. 키는 URL, 쿼리스트링, Referer, 브라우저 기록에 남지 않습니다.렌더링·가져오기 방어
마크다운은 raw HTML 없이 렌더링하고, 답변 속 링크에는
noopener noreferrer nofollow를 붙입니다. 가져오기 JSON은 스키마 검증을 거치고, 크기·개수 상한을 넘는 파일은 잘라서 버립니다. 조작된 파일이 탭을 멈추게 할 수 없습니다.의존성 고정과 입력 한도
런타임 의존성은 7개뿐이고, 모두 버전 범위 기호(
^,~) 없이 정확한 버전으로 고정했습니다.npm audit을 주기적으로 확인합니다. 메시지 32,000자, 시스템 프롬프트 8,000자, 가져오기 5MB·100개 대화로 입력을 제한해 한 번의 붙여넣기로 브라우저 저장소가 가득 차지 않게 합니다.배포 환경 하드닝
CSP(meta + 호스트 헤더),
X-Frame-Options: DENY,X-Content-Type-Options: nosniff,Referrer-Policy: strict-origin-when-cross-origin, 카메라·마이크·위치·결제를 끄는Permissions-Policy, COOP/CORP, HSTS를 배포 설정에 포함했습니다. 이 사이트는 iframe에 넣을 수 없고 object·form 전송도 차단됩니다.
입력 한도 (코드에 정의된 값)
- 메시지 32,000자
- 시스템 프롬프트 8,000자
- 가져오기 5MB · 100개 대화
- 대화 200개까지 보관
지키지 못하는 것
한계를 먼저 아는 편이 안전합니다
아래는 기능이 아니라 구조적인 한계입니다. 해당된다면 다른 도구나 추가 조치를 함께 쓰세요.
잠금 해제 중인 키는 메모리에 있습니다
암호화는 저장된 키를 보호합니다. 잠금을 해제한 동안 키는 평문으로 페이지 메모리에 있고, XSS가 성공하면 읽힐 수 있습니다. CSP는 심층 방어일 뿐이며, Next.js와 AdSense가 요구하는
'unsafe-inline'때문에 완전한 XSS 방어가 아닙니다.악성 브라우저 확장 프로그램
확장 프로그램은 페이지의 DOM, 네트워크 요청, 클립보드를 읽을 수 있습니다. 웹 페이지가 확장을 막을 방법은 없습니다. 필요한 확장만 남기고, 키를 다룰 때는 확장이 적은 프로필을 쓰세요.
대화 기록은 기본이 평문입니다
대화는 이 기기의 IndexedDB에만 저장되지만, 기본값은 평문입니다. 보안 잠금을 켠 뒤 '대화 기록 암호화'를 켜면 같은 암호구로 암호화되어 기기 백업·공용 PC 노출을 줄일 수 있습니다. 단, 암호구를 잊으면 키와 대화를 모두 복구할 수 없습니다.
로컬 악성코드와 OS 계정
같은 OS 계정으로 접근할 수 있는 사람이나 악성코드는 브라우저 저장소를 읽을 수 있습니다. 이 경우 웹 앱의 방어보다 OS 계정 잠금, 디스크 암호화, 최신 보안 업데이트가 더 중요합니다.
제공자 측 기록과 정책
요청이 도착한 뒤의 일은 제공자가 결정합니다. Anthropic, OpenAI, Google, OpenRouter의 로그, 보존 기간, 학습 정책은 KeyChat의 통제 밖입니다. 민감한 내용이라면 각 제공자의 정책을 먼저 확인하세요.
공용 기기에서는 위험이 커집니다
브라우저 데이터는 같은 OS 사용자에게 노출됩니다. 공용 PC에서는 저장 모드를 '탭을 닫을 때까지' 또는 '새로고침하면 삭제'로 두고, 사용 후 즉시 잠그고 저장된 키를 삭제하세요.
암호구를 잊으면 복구할 수 없습니다
암호구는 어디에도 저장되지 않기 때문에 KeyChat도 여러분도 키를 되살릴 수 없습니다. 잊었다면 저장된 키를 삭제하고 API 키를 다시 발급·입력해야 합니다. 버그가 아니라 설계입니다.
위협 모델
위협별 대응과 남는 위험
각 위협에 무엇으로 대응하고, 그래도 무엇이 남는지 표로 정리했습니다. '남는 위험'이 비어 있는 줄은 없습니다.
기기 분실·도난
선택적 키·대화 암호화(AES-256-GCM), 자동 잠금, 저장 모드 선택
잠금 해제된 상태로 기기를 되찾으면 키가 노출됩니다. 대화 암호화는 선택 사항입니다.
클라우드 백업·브라우저 동기화 유출
암호화 사용 시 localStorage에는 암호문만 저장. 암호구는 저장하지 않음(탭 기억 선택 시 sessionStorage만)
약한 암호구는 오프라인 무차별 대입에 노출될 수 있습니다. PBKDF2 600,000회는 비용을 높일 뿐 보장은 아닙니다.
공용 PC
저장 모드 3종(브라우저/탭 세션/메모리), 수동 잠금, 자동 잠금
같은 OS 계정을 쓰는 다음 사용자는 잠금 해제된 저장소를 볼 수 있고, 대화 암호화를 켜지 않았다면 대화 기록도 볼 수 있습니다.
악성 브라우저 확장
웹 페이지 수준에서는 차단 수단이 없습니다
잠금 해제 중인 키, 대화, 클립보드, 요청 내용을 읽을 수 있습니다.
XSS (마크다운·가져오기·서드파티 스크립트)
raw HTML 없는 마크다운, 링크 rel 제한, 가져오기 스키마 검증, CSP, AdSense 외 스크립트 금지
주입에 성공하면 메모리의 키와 대화를 읽을 수 있습니다. CSP는 'unsafe-inline'이 필요하고, 사용자 지정 엔드포인트를 위해 connect-src가 넓습니다.
공급망 (의존성 침해)
정확한 버전 고정, 런타임 의존성 최소화, npm audit 확인
빌드 시점에 실행되는 패키지나 네이티브 바이너리가 침해되면 막을 수 없습니다.
중간자 공격(MITM)
HTTPS 전용 배포 + HSTS. 키는 URL이 아니라 헤더로 전송
신뢰된 인증서를 가진 네트워크는 가로챌 수 있습니다. 제공자 측 로그는 통제 밖입니다.
제공자 측 기록·보존
요청은 사용자가 고른 제공자에게만 전송됩니다
제공자의 로그·보존 기간·정책은 KeyChat 통제 밖입니다.
암호구 분실
설정 시 명시적으로 경고. 복구 수단은 '저장된 키 삭제 후 재입력'
암호문은 복구할 수 없습니다. 이는 의도된 동작입니다.
기기 분실·도난
- 대응
- 선택적 키·대화 암호화(AES-256-GCM), 자동 잠금, 저장 모드 선택
- 남는 위험
- 잠금 해제된 상태로 기기를 되찾으면 키가 노출됩니다. 대화 암호화는 선택 사항입니다.
클라우드 백업·브라우저 동기화 유출
- 대응
- 암호화 사용 시 localStorage에는 암호문만 저장. 암호구는 저장하지 않음(탭 기억 선택 시 sessionStorage만)
- 남는 위험
- 약한 암호구는 오프라인 무차별 대입에 노출될 수 있습니다. PBKDF2 600,000회는 비용을 높일 뿐 보장은 아닙니다.
공용 PC
- 대응
- 저장 모드 3종(브라우저/탭 세션/메모리), 수동 잠금, 자동 잠금
- 남는 위험
- 같은 OS 계정을 쓰는 다음 사용자는 잠금 해제된 저장소를 볼 수 있고, 대화 암호화를 켜지 않았다면 대화 기록도 볼 수 있습니다.
악성 브라우저 확장
- 대응
- 웹 페이지 수준에서는 차단 수단이 없습니다
- 남는 위험
- 잠금 해제 중인 키, 대화, 클립보드, 요청 내용을 읽을 수 있습니다.
XSS (마크다운·가져오기·서드파티 스크립트)
- 대응
- raw HTML 없는 마크다운, 링크 rel 제한, 가져오기 스키마 검증, CSP, AdSense 외 스크립트 금지
- 남는 위험
- 주입에 성공하면 메모리의 키와 대화를 읽을 수 있습니다. CSP는 'unsafe-inline'이 필요하고, 사용자 지정 엔드포인트를 위해 connect-src가 넓습니다.
공급망 (의존성 침해)
- 대응
- 정확한 버전 고정, 런타임 의존성 최소화, npm audit 확인
- 남는 위험
- 빌드 시점에 실행되는 패키지나 네이티브 바이너리가 침해되면 막을 수 없습니다.
중간자 공격(MITM)
- 대응
- HTTPS 전용 배포 + HSTS. 키는 URL이 아니라 헤더로 전송
- 남는 위험
- 신뢰된 인증서를 가진 네트워크는 가로챌 수 있습니다. 제공자 측 로그는 통제 밖입니다.
제공자 측 기록·보존
- 대응
- 요청은 사용자가 고른 제공자에게만 전송됩니다
- 남는 위험
- 제공자의 로그·보존 기간·정책은 KeyChat 통제 밖입니다.
암호구 분실
- 대응
- 설정 시 명시적으로 경고. 복구 수단은 '저장된 키 삭제 후 재입력'
- 남는 위험
- 암호문은 복구할 수 없습니다. 이는 의도된 동작입니다.
표의 내용은 이 저장소의 실제 구현을 기준으로 작성했습니다. 구현이 바뀌면 이 표도 함께 고쳐야 합니다.
권장 설정
5분이면 끝나는 보안 설정
전부 켜야 하는 것은 아닙니다. 위험도가 높은 환경이라면 위에서부터 적용하세요.
12자 이상 암호구
앱이 12자 이상을 요구하고, 대소문자·숫자·기호가 섞이면 더 좋습니다. 길수록 오프라인 대입 비용이 커집니다.
자동 잠금 15분
기본적으로 15분을 권합니다. 자리를 자주 비우거나 이동 중이라면 5분으로 낮추세요.
공용 PC는 세션·메모리 모드
'탭을 닫을 때까지' 또는 '새로고침하면 삭제'를 선택하고, 사용 후 즉시 잠근 뒤 저장된 키를 삭제하세요.
AdSense 외 스크립트 추가 금지
사이트를 포크해 쓰더라도 분석 도구, 채팅 위젯, 폰트 CDN을 추가하지 마세요. 모든 스크립트는 잠금 해제된 키와 같은 출처에서 실행됩니다.
HTTPS 도메인 고정
HTTP 접속을 허용하지 말고 HSTS를 켜세요. 제공된
_headers와vercel.json에 HSTS가 들어 있습니다.대화 백업은 직접
기기 간 동기화는 없습니다. 중요한 대화는 JSON으로 내보내 보관하고, 공용 기기에서는 대화 기록을 삭제하세요.
취약점 신고
문제를 찾으면 알려주세요
보안 문제는 공개 이슈보다 이메일이 빠릅니다. 재현 방법, 영향 범위, 사용한 브라우저를 함께 보내주세요.
신고 범위
이 사이트의 정적 앱, 빌드 결과물, 배포 설정(헤더·CSP·리디렉션)이 대상입니다. Anthropic·OpenAI·Google·OpenRouter API 자체의 문제는 해당 제공자에 신고해 주세요.
포상금은 없습니다
이 사이트는 광고로 운영되는 개인 프로젝트라 포상금을 드릴 수 없습니다. 대신 신고 내용과 원하는 표기 방식을 협의해 감사 문구로 남기겠습니다.
공개 시점
수정 전에는 공개하지 말아 주세요. 재현 가능한 신고에는 90일의 수정 기간을 요청드리고, 수정 후 공개 일정은 함께 정합니다.
취약점 신고
- 연락처
- 이메일 (아래 버튼)
- 응답 목표
- 72시간 내 확인
- 수정 목표
- 유효한 신고는 90일 내 수정·완화
- 기계 판독용
- /.well-known/security.txt
더 알아보기
보안과 함께 보면 좋은 문서
데이터 처리 방침, 키 발급 절차, 그리고 보안 설정을 실제로 켜는 곳입니다.
KeyChat
내 API 키로 즐기는 AI 캐릭터 채팅. 채팅 사용료 없이 광고와 선택 구매로 운영됩니다.