테마
05. CSRF와 세션·쿠키 보안
로그인한 사용자의 브라우저는 이미 권한을 가진 상태다. CSRF 방어는 이 브라우저가 의도하지 않은 요청을 보내지 못하게 만들고, 세션과 쿠키는 그 권한이 함부로 재사용되지 않게 통제하는 작업이다.
학습 목표
- CSRF가 왜 성립하는지 설명할 수 있다.
SameSite,Secure,HttpOnly,__Host-같은 쿠키 속성의 역할을 이해한다.- CSRF 토큰, Origin 검증, 재인증이 각각 어떤 층위의 방어인지 설명할 수 있다.
- 오래된
IP 고정식 세션 보호의 한계를 이해한다.
1. CSRF는 어떤 상황에서 생길까?
핵심은 간단하다.
- 사용자는 이미 로그인되어 있다
- 브라우저는 세션 쿠키를 자동으로 보낸다
- 서버가 요청의 출처와 의도를 충분히 확인하지 않으면, 사용자가 의도하지 않은 상태 변경이 처리될 수 있다
2. 현재 기준에서 CSRF를 어떻게 봐야 할까?
예전보다 브라우저 기본 보안이 좋아진 것은 맞다.
특히 SameSite=Lax가 기본 동작에 가까워지면서 일부 크로스 사이트 요청은 자동으로 막힌다.
하지만 이것만으로 끝나지 않는다.
- 민감한 POST 요청
- 예외적으로 쿠키를 교차 사이트에서 보내야 하는 구조
- 레거시 브라우저나 복잡한 서브도메인 구성
- 브라우저 외 클라이언트와 함께 쓰는 환경
이런 경우에는 여전히 별도 CSRF 보호가 필요하다.
즉, 현재 기준은 SameSite 때문에 CSRF가 끝났다가 아니라 기본 방어층이 하나 늘어났지만 토큰과 검증은 여전히 중요하다에 가깝다.
3. CSRF 방어의 우선순위
3.1 1차: 상태 변경 요청에는 CSRF 토큰 + 출처 검증
가장 표준적인 방식은 Synchronizer Token 패턴이다.
- 서버가 예측 불가능한 토큰을 만든다
- 세션과 함께 저장한다
- 폼이나 요청 헤더에 함께 보낸다
- 서버가 요청마다 비교한다
중요한 점은 토큰 생성 방식이다.
- 현재는
random_bytes()같은 CSPRNG 기반 난수를 사용한다 - 시간값과 세션 ID를 해시해서 만드는 식의 단순 조합은 권장하지 않는다
토큰과 함께 요청 출처도 같이 확인한다.
Origin이 기대한 도메인인지 확인- 현대 브라우저 환경에서는
Sec-Fetch-Site같은 Fetch Metadata 헤더도 보조 판단에 활용 - 필요한 경우
Referer도 보조로 사용
다만 이것만으로 모든 환경을 커버한다고 생각하면 안 된다.
헤더 누락이나 프록시 환경 차이가 있기 때문이다.
3.2 2차: 쿠키 속성 기본값 강화
Secure, HttpOnly, SameSite는 세션과 CSRF 위험을 함께 줄이는 기본 방어층이다.
3.3 3차: 민감 동작은 재인증
아래 같은 기능은 CSRF 방어와 별개로 재인증이 유용하다.
- 비밀번호 변경
- 결제 수단 변경
- 관리자 권한 부여
- 계정 삭제
즉, 토큰이 맞다와 지금 사용자가 정말 이 동작을 하려는가는 다른 문제다.
4. 쿠키 속성은 최소 이 정도가 기본이다
| 속성 | 역할 | 기본 판단 |
|---|---|---|
Secure | HTTPS에서만 전송 | 세션 쿠키에는 사실상 필수 |
HttpOnly | JavaScript 접근 차단 | 세션 쿠키에는 기본값 |
SameSite | 교차 사이트 요청 전송 제어 | Lax 또는 Strict 검토 |
Path=/ + __Host- prefix | 도메인 범위 오용 줄이기 | 세션 쿠키에 권장 |
예시:
http
Set-Cookie: __Host-session=...; Secure; HttpOnly; SameSite=Lax; Path=/Partitioned 같은 최신 속성은 특정 3rd-party 임베드 시나리오에서 고려할 수 있지만, 일반 세션 쿠키의 기본값으로 설명할 필요는 없다.
5. 세션 보안에서 꼭 챙길 것
로그인 직후 세션 ID 재생성
세션 고정(Session Fixation)을 줄이려면 로그인 성공 후 세션 ID를 재발급해야 한다.
권한 상승 시에도 재생성
일반 사용자에서 관리자 모드로 전환되는 흐름처럼 권한 수준이 바뀌는 경우에도 세션을 다시 회전하는 편이 안전하다.
짧은 수명과 무효화
- 세션 TTL을 너무 길게 두지 않는다
- 로그아웃 시 서버 측에서 세션을 확실히 무효화한다
- 장시간 민감 조작 전에는 재인증을 요구한다
6. 왜 IP 고정은 현재 권장되지 않을까?
원문에는 접속 IP를 세션에 저장하고 비교하는 방식이 나온다.
과거에는 이해 가능한 보조 수단이었지만, 현재는 기본 방어로 권장하기 어렵다.
이유는 다음과 같다.
- 모바일 네트워크와 VPN 환경에서 정상 사용자 IP가 자주 바뀐다
- 같은 사용자의 요청도 NAT와 프록시를 거치며 출발지 표현이 달라질 수 있다
- 오탐 때문에 정상 사용자가 자주 로그아웃될 수 있다
지금은 다음 조합이 더 현실적이다.
Secure,HttpOnly,SameSite- 로그인/권한 상승 시 세션 회전
- 민감 동작 재인증
- 비정상 세션 패턴 모니터링
7. API 환경에서는 어떻게 할까?
SPA나 모바일 앱에서는 CSRF 방어 방식이 조금 달라진다.
- 쿠키 기반 인증이면 브라우저 요청에 대해 CSRF 고려가 필요하다
Authorization헤더 기반 토큰만 사용하면 전통적 CSRF 위험은 줄어든다- 그래도 저장형 XSS나 토큰 노출 문제는 별도로 남는다
즉, CSRF는 인증 방식을 포함해 전체 요청 모델에서 봐야 한다.
8. 흔한 잘못된 대응
| 잘못된 대응 | 왜 문제인가 | 더 나은 방식 |
|---|---|---|
| 토큰 없이 Referer만 확인 | 환경에 따라 누락 가능 | CSRF 토큰 + 출처 검증 병행 |
HttpOnly만 켜면 끝 | XSS가 있으면 악성 요청은 가능 | 쿠키 속성 + XSS 방어 + 재인증 |
IP 고정을 핵심 방어로 사용 | 오탐이 많고 사용자 경험 악화 | 세션 회전과 민감 조작 재인증 |
| 토큰을 예측 가능한 값으로 생성 | 추측 위험 | CSPRNG 난수 사용 |
9. PR 리뷰 체크리스트
- 상태 변경 요청에 CSRF 보호가 있는가
- 토큰이 예측 불가능한 난수로 생성되는가
- 세션 쿠키에
Secure,HttpOnly,SameSite가 적용되는가 - 세션 이름과 범위를 좁히기 위해
__Host-prefix를 검토했는가 - 로그인과 권한 상승 직후 세션 ID를 회전하는가
- 계정 삭제, 비밀번호 변경, 관리자 기능에 재인증이 필요한가
핵심 정리
- CSRF는 로그인된 브라우저가 의도하지 않은 요청을 보내는 문제다
- 현재도 토큰 기반 보호는 중요하며,
SameSite는 보조 방어층이다 - 세션 쿠키는
Secure,HttpOnly,SameSite를 기본으로 보고__Host-를 적극 검토한다 IP 고정보다 세션 회전, 재인증, 짧은 수명 관리가 현실적인 방어다