[주요정보통신기반시설 웹 애플리케이션 취약점 분석·평가 21일 완성 코스] 7강 — [Day 7] 크로스사이트 요청 위조 (CSRF)
[Day 7] 크로스사이트 요청 위조 (CSRF, Cross-Site Request Forgery)
안녕하세요! Hackerstory 공부방의 IT/보안 튜터 정다은입니다. 😊
지난 시간까지 클라이언트 측에서 실행되는 위험한 스크립트 공격(XSS)에 대해 다뤄보았습니다. 오늘은 그 연장선이자, 사용자의 **‘권한’**을 교묘하게 이용하는 대표적인 웹 취약점인 **[Day 7] 크로스사이트 요청 위조(CSRF)**에 대해 집중적으로 학습해 보겠습니다.
사용자가 나도 모르게 비밀번호를 변경하거나, 누군가에게 송금을 하고 있다면 얼마나 끔찍할까요? CSRF가 바로 그런 공격입니다. 원리부터 실무 진단법, 그리고 확실한 방어 수단까지 하나씩 파헤쳐 봅시다!
1. 개념 설명: CSRF(Cross-Site Request Forgery)란?
💡 CSRF의 기본 개념
**CSRF(크로스사이트 요청 위조)**는 로그인한 사용자의 브라우저가 의도하지 않은 악의적인 요청을 특정 웹 서버로 보내도록 강제하는 공격입니다.
이 공격의 핵심은 **"웹 서버는 브라우저가 보낸 요청을 사용자 본인이 직접 한 것으로 신뢰한다"**는 점입니다. 웹 애플리케이션이 세션 쿠키(Cookie) 등을 이용해 인증 상태를 유지할 때, 브라우저는 해당 도메인으로 요청을 보낼 때마다 자동으로 쿠키를 함께 전송합니다. 공격자는 이 동작 메커니즘을 악용합니다.
[공격 흐름 요약]
1. 피해자: 대상 사이트(vulnerable-bank.com)에 로그인 (세션 쿠키 보유)
2. 피해자: 공격자가 만든 악성 웹사이트(attacker.com) 방문
3. 악성 사이트: 피해자 브라우저를 통해 vulnerable-bank.com으로 비밀번호 변경/이체 요청 자동 송신
4. 대상 서버: 피해자의 유효한 쿠키가 첨부되어 들어왔으므로 정상 요청으로 판단하여 처리
⚔️ XSS vs CSRF 차이점 한눈에 보기
입문자분들이 가장 많이 헷갈려 하는 부분입니다.
| 구분 | XSS (Cross-Site Scripting) | CSRF (Cross-Site Request Forgery) |
|---|---|---|
| 공격 대상 | 클라이언트 (사용자의 브라우저) | 서버 (사용자의 권한을 도용하여 서버 상태 변경) |
| 주요 목적 | 쿠키 탈취, 악성 스크립트 실행, 정보 유출 | 사용자의 권한을 이용한 비인가 행위 수행 (수정/삭제/등록) |
| 핵심 원인 | 검증되지 않은 입력값 출력 | 요청의 출처(Origin) 및 의도 검증 미흡 |
2. 공격 예시 및 진단 방법
CSRF 공격이 실제로 어떻게 이루어지는지 HTTP 요청과 HTML 코드 수준에서 살펴보겠습니다.
🔍 공격 시나리오 예시
1) GET 방식의 취약한 애플리케이션 회원 정보 수정 페이지에서 이메일을 변경하는 요청이 아래와 같이 GET 방식으로 처리된다고 가정해 봅시다.
정상 요청:
GET /user/update_email.php?email=victim@email.com HTTP/1.1Host: vulnerable-bank.comCookie: PHPSESSID=abc123xyz...공격자의 악성 태그 (공격자 사이트나 게시판에 삽입):
<img src="https://vulnerable-bank.com/user/update_email.php?email=attacker@evil.com" width="0" height="0">피해자가 이 이미지 태그가 포함된 페이지를 열는 순간, 브라우저는 이미지 자원을 불러오기 위해
vulnerable-bank.com으로 GET 요청을 보냅니다. 이때 피해자의 세션 쿠키가 자동으로 첨부되어 이메일이attacker@evil.com으로 변경되어 버립니다.
2) POST 방식의 취약한 애플리케이션 POST 방식을 사용하더라도 안전하지 않습니다. JavaScript를 활용해 폼(Form)을 자동으로 제출시킬 수 있습니다.
- 공격자가 작성한 악성 페이지(attacker.com):
<form id="csrfForm" action="https://vulnerable-bank.com/user/change_pw.php" method="POST"> <input type="hidden" name="new_password" value="hacked1234!" /> <input type="hidden" name="confirm_password" value="hacked1234!" /> </form> <script> // 페이지가 로드되면 사용자 몰래 폼을 자동 제출 document.getElementById('csrfForm').submit(); </script>
🧪 실무 취약점 진단 방법
진단원 관점에서는 다음 사항을 체크하여 CSRF 취약점 유무를 판단합니다.
- 인증 요소 확인: 요청 내에 쿠키(Session ID) 외에 다른 검증 값(예: 예측 불가능한 토큰)이 존재하는가?
- 요청 재현 테스트:
- Burp Suite 등의 툴로 비밀번호 변경, 회원 탈퇴, 계좌 이체 등 주요 기능의 HTTP 요청을 수집합니다.
Referer헤더를 제거하거나 타 도메인으로 변경한 후 요청을 재전송합니다.- 별도의 Anti-CSRF 토큰 없이 요청이 정상적으로 처리된다면 CSRF 취약점 보유로 평가합니다.
3. 보안 대책 (보안 가이드 구현)
CSRF 공격을 완벽히 막기 위해서는 **"이 요청이 실제로 사용자가 의도하여 보낸 것인가?"**를 서버 측에서 검증해야 합니다.
① Anti-CSRF 토큰 (CSRF Token) 도입 (가장 확실한 대응책)
사용자 세션마다 난수화된 고유의 토큰을 생성하고, 중요한 요청을 보낼 때마다 이 토큰을 제출받아 서버에서 비교 검증합니다. 공격자는 피해자의 세션 쿠키는 자동으로 전송시킬 수 있지만, 타인의 세션에 발급된 CSRF 토큰 값은 알 수 없기 때문에 공격이 실패합니다.
- 서버 측 구현 예시 (PHP 예시):
<?php
session_start();
// 1. 토큰 생성 (페이지 로드시)
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
?>
<!-- 2. Form 내에 hidden 필드로 토큰 포함 -->
<form action="/user/change_pw.php" method="POST">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
<input type="password" name="new_password">
<button type="submit">비밀번호 변경</button>
</form>
<?php
// 3. 서버 측 처리 및 검증 logic
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
// 토큰이 일치하지 않거나 없는 경우 차단
http_response_code(403);
die("CSRF 토큰 검증 실패: 잘못된 요청입니다.");
}
// 정상 로직 수행...
}
?>
② 쿠키의 SameSite 속성 설정
최근 브라우저 환경에서는 쿠키 설정 시 SameSite 속성을 활용하여 타 사이트에서 발생하는 요청 시 쿠키 전송 여부를 제어할 수 있습니다.
SameSite=Strict: 타 사이트에서 유입되는 모든 Cross-site 요청에 쿠키를 전송하지 않음 (가장 안전하지만 사용자 편의성 고려 필요).SameSite=Lax: 기본값(최신 브라우저 기준). 안전한 상위 수준 이동(예: 단순 링크 클릭 GET 요청)을 제외한 이미지 로드, POST 폼 제출 시 쿠키 전송을 제한함.
Set-Cookie: JSESSIONID=xyz123456; Secure; HttpOnly; SameSite=Lax
③ 중요 기능에 대한 재인증 (Re-authentication)
비밀번호 변경, 회원 탈퇴, 자금 이체와 같은 민감한 작업에는 현재 비밀번호 재입력이나 **2차 인증(OTP, SMS 인증 등)**을 반드시 거치도록 설계합니다. 공격자가 사용자의 브라우저를 조종해 요청을 보내더라도, 사용자가 직접 비밀번호나 OTP를 입력하지 않는 한 처리가 불가능해집니다.
4. 요약 및 다음 챕터 예고
📝 오늘 학습한 내용 정리
- CSRF 개념: 로그인된 사용자의 권한을 이용해 서버가 의도치 않은 비인가 요청을 실행하도록 유도하는 취약점.
- 원인: 서버가 세션 쿠키만을 믿고, 요청이 어디서(Origin) 어떻게 유입되었는지 검증하지 않기 때문.
- 대응 방안:
- 예측 불가능한 Anti-CSRF 토큰 검증 (필수)
- 쿠키에
SameSite=Lax/Strict속성 적용 - 중요 기능 수행 시 현재 비밀번호 재입력/2FA 적용
🚀 다음 챕터 예고: [Day 8] 서버사이드 요청 위조 (SSRF)
오늘 공부한 CSRF가 *클라이언트(사용자 브라우저)*가 원치 않는 요청을 보내게 만드는 공격이었다면, 내일 배울 **[Day 8] SSRF(Server-Side Request Forgery)**는 공격자가 웹 서버 자체를 조종하여 내부망에 있는 다른 서버나 내부 자원으로 악의적인 요청을 보내게 만드는 심각한 공격 기법입니다!
클라이언트 측 요청 위조(CSRF)와 서버 측 요청 위조(SSRF)가 어떻게 다른지, 그리고 클라우드 환경에서 왜 SSRF가 유독 치명적인지 다음 시간에 아주 자세히 알아보겠습니다.
오늘도 고생 많으셨습니다. 내일 Day 8 강의에서 다시 만나요! 질문이 있다면 언제든 댓글로 남겨주세요! 👍
댓글 0
로그인하면 댓글을 작성할 수 있습니다.