웹 보안 실습: Cross‑Site Request Forgery (CSRF) 😱🛡️

발행: (2025년 12월 18일 오후 04:45 GMT+9)
7 min read
원문: Dev.to

I’m happy to translate the article for you, but I’ll need the full text you’d like translated. Could you please paste the content (or the portion you want translated) here? I’ll keep the source line exactly as you provided and preserve all formatting, markdown, and technical terms.

서론

안녕, 대학생 여러분! **Cross‑Site Request Forgery (CSRF)**에 대한 실습에 오신 것을 환영합니다. 이 공격은 교묘한 웹 공격 중 하나입니다. 온라인 은행에 로그인한 상태에서 악성 사이트를 새 탭으로 열었다고 상상해 보세요. 당신은 아무것도 클릭하지 않았지만, 악성 사이트가 당신의 브라우저에게 은행에 요청을 “강제”해서 해커에게 돈을 이체하도록 할 수 있습니다. 이는 브라우저가 다른 도메인에 대한 요청에 인증 쿠키를 자동으로 전송하기 때문입니다.

CSRF는 브라우저가 세션 쿠키를 신뢰하는 것을 이용해 다른 사이트에서 요청 위조를 하는 것입니다.

CSRF 작동 방식

주요 조건

  1. 사용자가 이미 로그인함 – 유효한 세션 쿠키가 존재합니다.
  2. 중요한 행동 (예: 금액 이체, 비밀번호 변경, 계정 삭제)이 GET 또는 POST 메서드를 사용하고 보호가 없을 경우.
  3. 브라우저가 모든 요청마다 자동으로 원본 도메인에 쿠키를 전송합니다.

공격 흐름 (고전적인 예시)

  1. 피해자가 대상 사이트에 로그인한 상태에서 악성 사이트를 방문합니다.
  2. 악성 사이트가 이미지나 숨겨진 폼 같은 요소를 로드하여 대상 사이트에 요청을 보냅니다.
  3. 피해자의 브라우저가 세션 쿠키와 함께 요청을 전송하여, 피해자 모르게 위험한 행동이 실행됩니다.

Ilustrasi alur serangan CSRF

취약점 예시

1. GET을 이용한 은행 이체

GET http://bank.com/transfer?jumlah=1000000&rekening_tujuan=12345678 HTTP/1.1
Host: bank.com
Cookie: session=abcd1234

악성 사이트가 숨겨진 이미지를 삽입할 수 있습니다:

![](http://bank.com/transfer?jumlah=5000000&rekening_tujuan=hacker123)

피해자가 악성 페이지를 열면 브라우저가 자동으로 해커 계좌로 이체 요청을 보냅니다.

2. 취약한 폼 (보호 없는 POST)

<form action="/ubah-email" method="POST">
    <input type="email" name="email" value="hacker@example.com">
    <button type="submit">Simpan</button>
</form>

악성 사이트:

<script>
    document.getElementById('jahat').submit();
</script>

악성 페이지를 연 피해자는 해당 폼을 자동으로 전송하게 되며, 그 결과 계정 이메일이 해커 것으로 변경됩니다.

3. GET을 이용한 “좋아요” 액션

Request 예시: GET /post?id=123&action=like.
악성 사이트가 이미지 태그를 추가할 수 있습니다:

![](http://target.com/post?id=123&action=like)

Source:

보호 메커니즘

CSRF 토큰 (가장 일반적이고 강력함)

  1. 서버가 세션당 또는 폼당 고유 토큰을 생성합니다.
  2. 토큰을 폼에 hidden 입력으로 혹은 별도 헤더에 포함시킵니다.
  3. 서버는 요청을 처리하기 전에 토큰을 검증합니다.
<form action="/simpan" method="POST">
    <input type="hidden" name="csrf_token" value="RANDOM_TOKEN">
    <button type="submit">Simpan</button>
</form>

토큰이 일치하지 않거나 없을 경우, 서버는 요청을 거부합니다.

SameSite 쿠키

SameSite=Lax 또는 SameSite=Strict 속성을 가진 쿠키를 설정하여 브라우저가 크로스‑사이트 요청 시 쿠키를 전송하지 않도록 합니다.

Set-Cookie: session=abcd1234; SameSite=Strict; Secure; HttpOnly

기타 좋은 실천 방안

  • POST를 사용해 상태를 변경하는 작업을 수행하고, GET은 피합니다.
  • Double Submit Cookie: 토큰을 쿠키와 폼 파라미터 두 곳에 모두 전송합니다.
  • 프레임워크 내장 보호 기능 활용 (Laravel, Django, Spring Security 등) – 이들은 자동으로 토큰을 추가하고 검증합니다.

보너스: CSRF vs XSS 🆚

항목CSRFXSS
대상브라우저가 쿠키를 신뢰함페이지에 스크립트 삽입
작동 방식유효한 쿠키로 요청을 강제함피해자 브라우저에서 실행되는 스크립트를 주입
일반적인 영향원치 않는 행동 (전송, 데이터 변경)데이터 탈취, 세션 하이재킹, 디페이스먼트
주요 완화 방안CSRF 토큰, SameSite 쿠키, POST입력값 정화, CSP, HttpOnly 쿠키

실습 및 랩

  • PHP에서 취약한 이체 폼을 만들고 이미지 태그를 이용한 CSRF 공격을 테스트합니다.
  • 수동 CSRF 토큰을 추가하고 다시 테스트합니다; 요청이 실패해야 합니다.
  • PortSwigger Web Security Academy에서 무료 랩을 시도해 보세요 (“CSRF” 검색).

토론

  • 왜 많은 은행이 CSRF 토큰OTP를 결합하나요?
  • 모든 state‑changing 엔드포인트가 보호되었는지 어떻게 확인할 수 있나요?

실습을 축하합니다! CSRF를 이해하고 적절한 보호를 적용하면 웹 애플리케이션이 은행 금고처럼 더 안전해집니다. 상태를 변경하는 행동을 항상 보호하고, 안전한 코딩 습관을 지속적으로 개발하세요. 🎉🔐

Back to Blog

관련 글

더 보기 »