1. CSRF 란
로그인은 내가 했는데 요청은 누가 만들었을까
어떤 쇼핑몰에 로그인했다고 가정한다. 로그인에 성공하면 서버는 사용자를 식별할 수 있는 세션을 만들고 브라우저에는 세션과 관련된 쿠키가 저장된다. 이후 배송지를 변경하면 브라우저에서 다음과 같은 요청이 발생할 수 있다.
POST /account/address
address=Seoul
서버는 요청과 함께 전달된 세션 쿠키를 확인한다. 정상적으로 로그인한 사용자의 요청이라는 것이 확인되면 배송지를 Seoul로 변경한다.
여기까지는 정상적인 과정이다.
그런데 사용자가 쇼핑몰에서 로그아웃하지 않은 상태로 다른 웹사이트에 접속했다고 가정한다. 이 사이트는 공격자가 준비한 사이트이다.
공격자는 피해자의 쇼핑몰 비밀번호도 모르고 세션 쿠키도 가지고 있지 않다. 따라서 공격자가 자신의 컴퓨터에서 쇼핑몰에 요청을 보내봤자 피해자의 계정으로 처리되지 않는다.
하지만 공격자는 다른 방법을 생각할 수 있다. 내가 피해자의 인증 정보를 가지고 있지 않다면 이미 로그인되어 있는 피해자의 브라우저가 요청을 보내게 만들면 되지 않을까. 이 아이디어에서 CSRF가 시작된다. 공격자는 비밀번호를 훔칠 필요가 없다. 공격자가 원하는 것은 피해자의 세션 쿠키 자체가 아닐 수 있다.
피해자의 브라우저는 이미 쇼핑몰에 로그인되어 있다. 그리고 브라우저는 조건이 맞으면 해당 사이트로 요청을 보낼 때 쿠키를 자동으로 함께 전송한다. 공격자는 자신이 준비한 페이지를 통해 피해자의 브라우저가 다음과 같은 요청을 보내도록 유도한다.
POST /account/address
address=AttackerAddress
이 요청이 쇼핑몰 서버에 도착한다. 쇼핑몰 서버가 확인한 요청에는 피해자의 정상적인 로그인 세션이 존재할 수 있다. 서버 입장에서는 고민할 지점이 생긴다.
이 사용자가 로그인했는가. -> 로그인되어 있음. -> 그렇다면 주소를 변경함.
하지만 여기에는 빠진 질문이 하나 있다. "이 사용자가 정말 이 주소로 변경하겠다고 요청한 것인가."
CSRF는 인증된 사용자라는 사실과 사용자가 실제로 해당 행동을 의도했다는 사실이 서로 다르다는 점을 이용한다. 누가 요청을 보냈는지가 중요하다 CSRF를 처음 공부하면 공격자가 피해자의 계정으로 요청을 보낸다고 생각하기 쉽다. 하지만 그것과는 조금 다르다. 공격자가 자신의 브라우저에서 피해자의 요청을 보내는 것이 아니라 피해자의 브라우저가 요청을 보내도록 유도한다.
공격자 사이트 → 피해자 브라우저 → 취약한 쇼핑몰
실제 HTTP 요청의 출발점은 피해자의 브라우저이다. 피해자의 브라우저에는 이미 로그인 상태가 존재하기 때문에 조건에 따라 인증 정보가 요청에 포함될 수 있다. 그래서 Cross Site Request Forgery라는 이름이 붙는다. 다른 사이트에서 시작된 공격자의 의도가 피해자의 브라우저를 거쳐 정상 사이트에 요청으로 전달되는 것이다.
버튼을 직접 누르지 않아도 요청은 만들어질 수 있다 웹에서 요청을 만드는 방법은 사용자가 버튼을 직접 클릭하는 것만 있는 것이 아니다. HTML Form을 제출하거나 브라우저가 특정 리소스를 불러오는 등의 과정에서도 HTTP 요청이 발생한다. 따라서 취약한 애플리케이션이 요청의 출처와 사용자의 의도를 충분히 검증하지 않는다면 피해자는 자신이 어떤 요청을 보냈는지 인지하지 못할 수도 있다.
예를 들어 공격자가 준비한 페이지에 접속했을 뿐인데 브라우저에서 계정 정보 변경 요청이 발생하도록 구성된 상황을 생각할 수 있다. 피해자가 보는 화면과 실제 브라우저가 보내는 HTTP 요청이 반드시 같지는 않다는 점이 CSRF를 이해하는 데 중요하다. GET과 POST의 차이만으로 해결되지 않는다 중요한 기능을 GET으로 구현하지 않고 POST를 사용하면 CSRF가 해결된다고 생각할 수도 있다. 하지만 POST 요청 역시 브라우저에서 생성할 수 있다.
따라서 "GET을 사용했으니 위험함" 또는 "POST를 사용했으니 안전함" 과 같이 구분해서는 안 된다. 중요한 것은 HTTP Method 자체보다 서버가 해당 요청이 정상적인 사용자 흐름에서 만들어진 것인지 검증하는가이다. 특히 데이터 삭제 계정 정보 변경 비밀번호 변경과 같이 서버의 상태를 변경하는 기능에는 별도의 CSRF 방어가 필요하다.
2. CSRF Token은 왜 필요한가
그렇다면 서버는 로그인한 사용자와 공격자가 만들어낸 요청을 어떻게 구분할 수 있을까. 대표적인 방법이 CSRF Token이다. 사용자가 정상적으로 페이지에 접근했을 때 서버가 예측하기 어려운 값을 제공한다고 가정한다.
csrf_token=a8f31c…
정상적인 주소 변경 요청에는 이 값이 함께 들어간다.
POST /account/address
address=Seoulcsrf_token=a8f31c…
서버는 세션 쿠키만 확인하는 것이 아니라 CSRF Token도 함께 확인한다. 공격자는 피해자의 브라우저가 쇼핑몰에 요청하도록 유도할 수 있더라도 정상 페이지에 포함된 예측하기 어려운 Token 값을 알 수 없다면 올바른 요청을 만들기 어려워진다. 즉 서버의 질문이 하나 더 생기는 것이다. 이 사용자가 로그인했는가. 그리고 이 요청에는 정상적인 사용자 흐름에서 발급한 값이 존재하는가. 두 조건을 함께 확인하면서 공격자가 다른 사이트에서 임의로 만들어낸 요청을 구분할 수 있게 된다.
3. SameSite가 등장한 이유
현대 브라우저에서는 Cookie의 SameSite 속성도 CSRF 방어에서 중요한 역할을 한다. CSRF의 중요한 전제 중 하나는 다른 사이트에서 시작된 요청에 사용자의 인증 쿠키가 함께 전달될 수 있다는 것이다. SameSite는 이러한 Cross Site 상황에서 쿠키를 어느 범위까지 전송할 것인지 제어한다. Strict는 Cross Site 상황에서 쿠키 전송을 강하게 제한한다. Lax는 일부 Cross Site 요청에서는 쿠키 전송을 허용하면서 여러 위험한 상황에서는 제한한다. None은 Cross Site 요청에서도 쿠키를 사용할 수 있도록 하며 Secure 속성과 함께 사용해야 한다. SameSite 설정을 적절하게 사용하면 다른 사이트에서 만들어진 요청에 인증 쿠키가 포함되는 것을 제한하여 CSRF의 성립 가능성을 낮출 수 있다.
4. CSRF와 XSS는 무엇이 다를까
CSRF와 XSS를 비교하면 CSRF의 특징이 더 명확해진다. XSS에서는 공격자가 취약한 사이트의 페이지에서 JavaScript를 실행시키는 것이 핵심이다. CSRF에서는 공격자의 코드가 취약한 사이트 내부에서 실행될 필요가 없다. 공격자가 원하는 것은 피해자의 브라우저가 특정 요청을 보내게 만드는 것이다.
XSS = 공격자가 원하는 코드가 피해자 브라우저에서 실행됨
CSRF = 공격자가 원하는 요청을 피해자 브라우저가 전송함
그래서 CSRF에서는 공격자가 서버의 응답을 직접 읽지 못하더라도 공격이 의미를 가질 수 있다. 예를 들어 공격자의 목적이 배송지 변경이라면 변경 결과 페이지의 내용을 읽는 것보다 변경 요청 자체가 서버에서 처리되는 것이 중요하다. 로그인과 사용자의 의도는 다르다 CSRF의 핵심은 결국 인증과 요청의 의도를 구분하는 것이다.
세션 쿠키는 이 요청을 보내는 브라우저가 어떤 사용자로 인증되어 있는지를 알려준다. 하지만 쿠키만으로는 사용자가 정말 그 행동을 원했는지까지 알 수 없다.
정상적인 상황은 다음과 같다.
사용자 의도
→ 사용자 브라우저
→ 인증 정보와 정상 요청
→ 서버
CSRF가 발생하면 다음과 같이 바뀐다.
공격자 의도
→ 피해자 브라우저
→ 피해자의 인증 정보와 공격자가 만든 요청
→ 서버
두 요청 모두 서버에는 인증된 사용자의 브라우저에서 온 것처럼 보일 수 있다. 따라서 서버는 세션 쿠키만 믿는 것이 아니라 CSRF Token과 적절한 SameSite Cookie 설정 Origin 검증 등 추가적인 방어 방법을 사용해야 한다. CSRF는 피해자의 계정 정보를 훔쳐 로그인하는 공격이 아니다. 이미 로그인한 피해자의 브라우저가 가진 인증 상태를 이용해 피해자가 의도하지 않은 요청을 정상적인 요청처럼 서버에 전달하는 공격이다. 로그인한 사람은 피해자이지만 요청을 의도한 사람은 공격자라는 점이 CSRF를 이해하는 가장 중요한 부분이다.
'보안' 카테고리의 다른 글
| SSRF (0) | 2025.05.31 |
|---|---|
| IDOR 취약점 (0) | 2025.05.26 |
| XSS - Stored Cross-Site Scripting (0) | 2025.05.20 |
| 손으로 배우는 해킹(Nomartic Youtube) (0) | 2025.03.11 |
| 기초 네트워크 (0) | 2025.03.11 |