CSRF (Cross-site request Forgery)

hi2li·2026년 3월 19일

로그인만 했을 뿐인데 돈이 빠져나간다?

  • 사용자가 은행 사이트에 로그인해둔 상태에서 다른 사이트 하나를 추가로 방문했는데 갑자기 계좌에서 100만원이 송금될 수 있다.
  • CSRF공격을 통해 위의 시나리오가 발생가능하다.

CSRF공격흐름

[1] 사용자가 은행사이트에 로그인

[2] 서버가 세션을 생성하고 세션ID를 발급

[3] 브라우저에는 해당 쿠키가 저장됨. (이후 그 은행사이트 들어갈 때 자동으로 쿠키를 첨부함)

[4] 사용자가 어쩌다가 공격자가 만들어둔 악성 사이트에 접속 → 이 사이트에는 “사용자의 계좌에서 100만원을 송금하는” 악성요청코드가 포함되어있음.

[5] 스크립트로 해당 요청코드를 실행시킴

[6] 브라우저는 동일하게 은행사이트로의 요청이므로 쿠키를 자동으로 첨부하여 요청을 보낸다.

[7] 은행서버는 “아 이거 ~~맞네 “확인하고 100만원을 이체함.

그림으로 보기!

왜 이런일이 가능한가?

→ 쿠키와 세션이다.

  • 쿠키는 브라우저에 저장되는 데이터로, 로그인 상태 유지를 위해 사용된다.
  • 특히 세션 기반 인증에서는 쿠키에 세션을 식별하는 세션 ID가 저장된다.
  • 보통의 형태
# 서버가 로그인된 세션을 abc123이라는 세션아이디로 매핑해뒀고, 그걸 가지고있음.
Cookie: session=abc123
  • 서버는 이 세션 ID를 통해 해당 사용자를 식별하고 로그인 상태를 유지한다. (”아 이거 ~~한테 온거 맞구나. 그 세션이구나)
  • 한 편, 브라우저는 요청을 보내는 곳에 관계없이 요청 대상 도메인에 해당하는 쿠키가 존재하면 해당 쿠키를 자동으로 첨부하는데 CSRF는 이 점을 이용한다.

결국 CSRF란?

→ 사용자의 인증 상태를 이용해 의도하지 않은 요청을 보내게만드는 공격이다.

그럼 어떻게 막을까?

→ CSRF-token 을 사용하여 CSRF공격을 막을 수 있다.

  • CSRF Token : “이 요청이 진짜 사용자가 보낸 요청이 맞는지 확인하는 비밀값”

동작 흐름

[1] 사용자가 페이지 요청 (로그인 상태)

[2] 서버가 HTML + CSRF 토큰 같이 내려줌

 <input type="hidden" name="csrf_token" value="abc123">

[3] 사용자가 폼 제출

[4] 브라우저는 요청과 함께 CSRF토큰을 서버로 전송

[5] 서버는 세션에 저장된 토큰과 요청에 포함된 토큰을 비교하여

→ 일치하면 정상 요청 처리

→ 불일치하면 요청 거부

CSRF Token

  • 토큰은 서버가 생성한 랜덤한 값이기 때문에 공격자가 그것을 맞출 수 없다.
    • 서버는 본인이 만든 정상토큰을 HTML에 넣어서 준다.
    • 즉 처음 접속할 때 HTML이 처음 로드 되면서 랜덤토큰을 받고, 그다음에 스크립트나 요청등이 해당 토큰을 사용하여 요청된다.
    • 이때 서버는 세션과 토큰을 매핑에서 저장한다.
<form action="/transfer" method="POST">
  <input type="hidden" name="csrf_token" value="x8F3k2L9">
</form>
  • 서버는 자신이 만든 토큰과 일치하는지 확인한다.

공격자가 동일한 토큰을 만들어낼 수 없는 이유

  • 서버는 사용자 세션마다 CSRF 토큰을 따로 랜덤으로 생성해 저장하고, 요청 시 해당 세션에 매핑된 토큰과 비교한다.
    공격자는 피해자의 세션에 해당하는 토큰을 알 수 없기 때문에 요청을 위조할 수 없다.

→ “토큰은 세션과 1:1로 묶여 있어서, 남의 토큰은 쓸 수 없다”

  • 그러면 탈취하면 되는거 아닌가?

공격자가 CSRF-Token을 탈취할 수 없는이유

-> Same-origin Policy
- 보통 브라우저에서 프로토콜, 도메인, 포트가 같은 출처를 갖는다.
- → URL구조에서 http부분이 프로토콜, naver.com 부분이 도메인, 8080부분이 포트이다.

  • 예를들어 아래와 같은 경우에는 프로토콜, 도메인, 포트(디폴트값으로 들어가있음)가 전부 같음

    	•	https://bank.com
    	•	https://bank.com/account
  • 하지만 아래는 다름

    http://bank.com  ← 프로토콜 다름
    https://sub.bank.com ← 도메인 다름
    https://bank.com:8080 ← 포트 다름

    이런식으로 출처(프로토콜, 도메인, 포트)가 다르면 브라우저가 읽기를 제한한다.

    → 즉 토큰이 HTML에 있는데 origin이 다르기 때문에 공격자는 그걸 읽을 수없고, CSRF-token을 탈취할 수 없게 된다.

CSRF attack이 성공하기 위한 조건

  • 쿠키만으로 인증하는 구조
  • 토큰 검증 없음
  • Origin / Refere검증없음

한 줄 핵심!

“브라우저가 쿠키를 자동 첨부하는 특성을 이용해 요청을 위조하는 공격이 CSRF이며, 이를 막기 위해 세션 기반 CSRF 토큰 검증이 필요하다.”

profile
갈망하자

0개의 댓글