1. CSRF 공격이란?
- Cross-Site Request Forgery (사이트 간 요청 위조 공격)
- 공격자가 사용자를 속여, 위조된 사이트에서 클릭을 통해 의도하지 않은 요청을 보내게 만드는 공격
- ✅ 사용자가 로그인한 상태일 경우, 브라우저가 해당 사이트에 요청을 보낼 때 세션 쿠키를 자동으로 포함하는 점을 이용함
예시) 은행 위조 사이트
더보기
- 사용자가 은행 웹사이트에서 계좌이체를 마친 뒤에도 로그인 세션이 유지되고 있다고 가정한다.
- 이후 사용자는 이메일을 확인하던 중, 모르는 사람이 보낸 링크를 별다른 의심 없이 클릭한다.
- 링크를 통해 이동한 웹페이지에는 “버튼을 누르면 상품을 받을 수 있다”는 문구가 표시되어 있었음
- 사용자는 해당 버튼을 클릭한다.
- 하지만 이 버튼은 실제로는 공격자가 미리 만들어둔 은행 송금 요청을 전송하도록 구성되어 있다.
- 송금 요청은 인증된 사용자만 접근할 수 있는 보안 URL이지만, 사용자의 브라우저에는 은행 로그인 세션 쿠키가 아직 남아 있다.
- ❗️ 브라우저는 은행 웹사이트로 요청을 보낼 때 해당 쿠키를 자동으로 함께 전송한다.
- 사용자의 브라우저가 인증 쿠키를 자동으로 전송하는 특성을 이용해, 사용자가 의도하지 않은 송금 요청을 은행 서버에 전달한다.
- ❗️ 공격자는 사용자의 쿠키 값을 직접 읽거나 탈취하지 않아도 된다.
- 은행 서버에 별도의 CSRF 방어가 없다면, 서버는 이 요청을 정상적으로 로그인한 사용자가 보낸 요청으로 오인할 수 있다.
- 그 결과 사용자는 자신도 모르게 공격자에게 금액을 송금하는 피해를 입게 된다.
2. CSRF 방어 방법
Safe HTTP Method 준수
- CSRF 공격을 방지하기 위해 서버의 상태를 변경하지 않는 안전한 메서드를 사용해야 함
- ✅ GET, HEAD, OPTIONS, TRACE
Synchronizer Token Pattern
- 사용자가 상태 변경 요청을 보낼 때, 서버가 발급한 CSRF 토큰을 함께 제출하도록 하는 방식
- 서버는 예측하기 어려운 CSRF 토큰을 생성하고, 사용자 세션에 보관함 (HttpSessionCsrfTokenRepository)
- ✅ 브라우저는 '/csrf' 요청을 통해 CSRF 토큰을 전달받음
- 클라이언트는 상태 변경 요청 전에 서버가 발급한 CSRF 토큰을 발급받아야 함
- ❗️ Same-Origin Policy 때문에 공격자는 읽지 못함.
- ➡️ CORS 정책을 함부로 풀지 않도록 설정해야 함
- ✅ CSRF Token은 브라우저에 쿠키 형태로 보관되지 않습니다
- 브라우저 메모리 어딘가에 저장됨
- 요청 시, 'X-CSRF-TOKEN'라는 HTTP 요청 헤더로 함께 전송함
- ➡️ 요청으로 들어온 _csrf 값의 비교를 통해 유효성을 검증합니다.
동작 과정
더보기
- 서버가 사용자 세션과 연결된 CSRF 토큰을 생성한다.
- 정상 웹페이지에 CSRF 토큰을 포함해 클라이언트에 전달한다.
- 클라이언트는 상태 변경 요청에 CSRF 토큰을 함께 전송한다.
- 서버는 자신이 보관한 토큰과 요청으로 전달된 토큰을 비교한다.
- 토큰이 일치하면 요청을 허용하고, 없거나 일치하지 않으면 거부한다.
SameSite Attribute
- 브라우저가 쿠키를 교차 사이트 요청에 포함할지 제한하는 쿠키 속성
- ✅ Strict: 동일 사이트 요청에만 쿠키 전송
- ✅ Lax: 동일 사이트 요청에만 쿠키 전송 (단, 외부 링크의 최상위 GET 이동만 허용)
- ➡️ 공격자 사이트에서 발생한 상태 변경 요청에 인증 쿠키가 자동으로 첨부되는 것을 제한하므로 CSRF 방어의 효과를 얻음.
Content-Type 검증
- 서버가 상태 변경 요청에서 허용할 Content-Type를 제한해 CSRF 공격 경로를 줄이는 보조 방어 방식
- ➡️ application/json 형태로 보내면 CORS Preflight 검증이 발생하므로 위조 사이트의 요청을 제한할 수 있음
3. CSRF 고려사항
Login
- 공격자가 피해자의 브라우저를 이용해 공격자 자신의 계정으로 로그인 요청을 보내는 공격
- 피해자는 자신이 정상적으로 로그인한 것으로 생각하고 민감정보 입력을 의심없이 입력할 수 있음
- 그러나 실제로는 공격자 계정에 로그인된 상태이므로, 입력한 정보가 공격자 계정에 저장될 수 있음
- ➡️ 로그인 요청에도 CSRF 토큰 검증 적용
- ➡️ 로그인 성공 시 기존 세션 교체 (Session Fixation 방지)
- ➡️ session timeout: 장시간 방치된 세션의 위험을 줄이기
Session Timeout
- CSRF Token은 session에 포함됩니다.
- ✅ 세션이 만료되면 인증 정보와 함께 기존 CSRF 토큰도 무효화됨
- ➡️ session이 곧 만료되면 사용자에게 알리기 (재로그인 안내)
- ➡️ CSRF Token을 쿠키에 저장하기
- 공격자에 의해 접근이 가능하므로 여러 보안장치를 가져야 합니다
- CORS, SameSite, Secure, 제한적 Path 및 Domain 등
Multipart
- Multipart request로부터 CSRF 공격을 방어하는데 문제가 있습니다.
- ⚠️ CSRF Token을 Body에 둘 경우, 확인을 위해 Body를 읽는 순간 Multipart 파일이 업로드됨 (자원 소비)
- ⚠️ CSRF Token을 URL에 둘 경우, 토큰이 노출될 위험이 있음
- ➡️ CSRF Token을 X-CSRF-TOKEN 요청 헤더에 두기
참고
'Spring > Spring Security' 카테고리의 다른 글
| [Spring Security] 5-3. 보안: HTTP Requests (0) | 2023.10.14 |
|---|---|
| [Spring Security] 5-2. 보안: Security HTTP Response Headers (3) | 2023.10.14 |
| [Spring Security][KoLiving] 4-5. BlackList Token (0) | 2023.10.03 |
| [Spring Security][KoLiving] 4-4. RefreshToken Rotation (0) | 2023.10.03 |
| [Spring Security][KoLiving] 4-3. RefreshToken (2) | 2023.10.03 |