웹 브라우저에 저장되는 쿠키
로그인을 진행하면서 세션-쿠키 방식으로 구현했다.
이때 세션ID를 브라우저의 쿠키에 저장하게 되고, 브라우저와 서버는 쿠키 정보를 주고받는다.
쿠키를 저장하는 공간을 전통적으로 쿠키 통(COOKIE_JAR)라고 부른다.
브라우저는 헤더로 Set-Cookie를 받으면 COOKIE_JAR를 업데이트 해야한다.
쿠키의 특징
- 쿠키는 브라우저의 신원으로, 같은 도메인에서 동일한 쿠키가 사용된다. 그래서 동일한 쿠키를 사용하면 동일한 사용자라고 인식한다. 이는 보안 측면에서 문제가 될 수 있다.
- 같은 도메인 내에서는 모든 API 요청에 자동으로 세션 쿠키가 포함된다.
- 이는 개인 프라이빗 데이터가 유출되는 것이다.
- 공격자가 서버나 브라우저를 이용해 쿠키를 탈취할 가능성이 있다.
쿠키의 한계
이렇게 보안 기능이 따로 없는 쿠키를 위해 실무적으로 방어를 해줘야한다.
- 브라우저 레벨: SOP(기본), CORS 정책 적절 설정
- 쿠키 옵션:
HttpOnly,Secure,SameSite - 서버 쪽: CSRF 토큰, Origin/Referer 검사, 출력 이스케이프, CSP로 XSS 차단
동일 출처 정책(SOP)
일단 감사하게도, 브라우저 레벨에서 동일 출처 정책(SOP) 기능이 장착되어있다. 서버가 Set-Cookie로 세션을 내려주면 브라우저가 동일 출처로 자동 저장·전송한다. 동일 출처란 같은 origin, 같은 호스트명, 같은 포트를 가진 웹페이지에만 전송을 허용하는 것이다.
왜 SOP가 중요하냐면
- SOP는 다른 출처(교차 출처)의 스크립트가 해당 응답을 읽지 못하게 막는다.
- 즉, 공격자 페이지에서 요청을 보내는 것 자체는 (브라우저가 허용하면) 가능하더라도, 응답을 읽어 처리하는 단계를 차단함으로써 데이터 유출을 막는다. 이 방법으로, 웹사이트의 프라이빗 데이터가 그 웹사이트에만 유지되고 다른 서버의 공격자에게 유출되지 않을 수 있다.
SOP가 못막는 것
SOP는 교차 출처 간의 호출을 막지만, 이런 SOP가 막지 못하는 게 있다. 폼 전송과 같은 교차 사이트 요청 위조(CSRF) 공격을 가능하게 한다. 즉, 공격자가 사용자의 브라우저로 요청을 보내게 해서 쿠키는 자동으로 포함될 수 있는 것이다.
<!-- 공격자가 만든 페이지 -->
<form action="https://bank.example/add" method="POST">
<input name="amount" />
<button>OK</button>
</form>
CSRF 방어
SOP의 한계로 인해 CSRF 방어(토큰, SameSite 등)가 필요하다. 폼 전송을 위한 안전한 솔루션은 SameSite 쿠키이다. 만약 서버가 자신의 쿠키를 SameSite로 설정해두면, 브라우저는 폼 전송이 교차 차이트일 때 그 쿠키를 전송하지 않는다.
- Set-Cookie: SameSite=Lax
- SameSite 속성은 Lax, Strict, None 3가지이다.
| 속성 | 교차 사이트 GET 요청 (링크 클릭 등) | 교차 사이트 POST / AJAX / iframe 등 | 동일 사이트 GET/POST 요청 | 특징 / 주의점 |
|---|---|---|---|---|
| Lax | ✅ 쿠키 전송 (탑레벨 내비게이션의 안전한 GET은 허용) | ❌ 쿠키 전송 안 함 | ✅ 쿠키 전송 | 기본값. 일반적인 사용성(링크 통한 로그인 유지)과 보안을 균형 있게 지원 |
| Strict | ❌ 쿠키 전송 안 함 | ❌ 쿠키 전송 안 함 | ✅ 쿠키 전송 | 가장 보안 강력. 교차 사이트에서 들어오는 모든 요청에 쿠키 차단 → 외부 리디렉션(OAuth, 결제) 깨질 수 있음 |
| None | ✅ 쿠키 전송 | ✅ 쿠키 전송 | ✅ 쿠키 전송 | 교차 사이트 요청에도 항상 쿠키 전송. 반드시 Secure와 함께 사용해야 하고 CSRF 방어(토큰, Origin 검증 등) 필요. 외부 연동(소셜 로그인, 결제 콜백 등) 시 사용 |
XSS 공격의 방어막
HttpOnly- 브라우저 내부에서만 사용 (요청 시 자동 포함)
- JS 코드에서는 접근 불가
Content-Security-Policy(CSP): 콘텐츠 보안 정책
콘텐츠 보안 정책
XSS 공격의 방어막 중 하나는 Content-Security-Policy(CSP) 헤더이다. 이 헤더의 전체 사양은 복잡하지만, 가장 단순한 예시는 default-src 키워드 뒤에 공백으로 구분된 서버 목록을 설정하는 것이다.
Content-Security-Policy: default-src 'self'
브라우저에게 리스트된 출처를 제외한 CSS, JS, 이미지 등 어떤 리소스도 로드하지 말라고 요청한다.
만약 공격자가 페이지에 <script>를 추가했더라도 브라우저는 그 스크립트를 로드하거나 실행하지 않는다.
[로그인 요청 시 세션-쿠키 설정]
