
고급 PHP 프로그래밍 – 웹 보안 – 크로스 사이트 요청 위조(CSRF) 방지
안녕하세요~ 😊
오늘은 웹 보안 시리즈 세 번째 주제로, CSRF(크로스 사이트 요청 위조) 방지 방법을 소개해드릴게요!
이 공격은 마치 친구를 사칭해 내 계좌에서 돈을 빼가는 것처럼, 사용자의 신뢰를 이용해 공격자가 의도하지 않은 요청을 실행하게 만드는 방식이에요.
조금 무서운 이야기 같죠?
하지만 걱정 마세요! PHP로 안전한 웹사이트를 만들 수 있는 실질적인 대책을
비유와 예제로 아주 알기 쉽게 설명드릴게요~! 💪✨
CSRF란 무엇인가요?
**Cross-Site Request Forgery (CSRF)**란, 사용자가 로그인된 상태를 악용해
악성 웹페이지가 사용자의 권한으로 특정 요청을 보내도록 유도하는 공격 방식입니다.
🔥 비유하자면?
은행에 로그인한 상태로 쉬고 있는데, 누군가 몰래 내 손을 잡고
이체 버튼을 클릭하게 만드는 것과 같아요!
예제: 어떻게 공격이 일어날까요?
취약한 PHP 코드
// 회원 탈퇴 처리
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$userId = $_POST['user_id'];
deleteUser($userId);
}
공격자가 만든 외부 사이트
<form action="https://www.example.com/delete.php" method="POST">
<input type="hidden" name="user_id" value="123">
<input type="submit" value="클릭만 해주세요!">
</form>
<xss-script>
document.forms[0].submit();
</xss-script>
사용자가 이미 로그인된 상태에서 이 페이지를 방문하면
의도치 않게deleteUser(123)
이 실행되어 버리는 거예요 😱
CSRF 공격의 위험성
위험 요소 | 설명 |
---|---|
정보 변경 | 이메일, 비밀번호 무단 변경 |
계정 탈퇴 | 회원 탈퇴나 거래 취소 실행 가능 |
결제 조작 | 포인트 충전, 결제 요청까지 가능 |
권한 탈취 | 관리자 권한 변경도 가능 |
CSRF 방지 방법
✅ 1. CSRF 토큰 사용 (가장 강력!)
폼을 생성할 때 랜덤 토큰을 숨겨놓고, 서버에서 일치하는지 검증하는 방식입니다.
📌 폼에 CSRF 토큰 포함시키기
// token 생성
session_start();
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
<!-- 폼 내부 -->
<form method="POST" action="delete.php">
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
<input type="submit" value="회원 탈퇴">
</form>
📌 서버에서 토큰 검증
session_start();
if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) {
die('잘못된 접근입니다!');
}
공격자는 이 토큰 값을 알 수 없기 때문에, 공격 자체가 실패하게 돼요! 🚫
✅ 2. 요청 메서드 제한 (GET 금지)
- 중요한 요청은 반드시 POST, PUT, DELETE로 제한해야 해요!
- GET 요청만으로 상태를 바꾸는 API는 매우 위험합니다.
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
die('허용되지 않은 접근 방식입니다!');
}
✅ 3. Referer 또는 Origin 검사
HTTP 헤더의 Referer 또는 Origin 값을 검사해서
정상적인 출처에서 온 요청인지 확인하는 방법도 있어요.
$referer = $_SERVER['HTTP_REFERER'] ?? '';
if (strpos($referer, 'https://www.mywebsite.com') !== 0) {
die('의심스러운 요청이 감지되었습니다.');
}
완벽한 방식은 아니지만, 기본적인 방어막은 됩니다!
✅ 4. SameSite 쿠키 설정
브라우저에서 크로스사이트 요청에 쿠키를 전송하지 않도록 설정할 수도 있어요.
setcookie("session_id", $value, [
'samesite' => 'Strict',
'secure' => true,
'httponly' => true
]);
Strict
: 다른 사이트에서 요청할 때 쿠키 전송 안 됨 (가장 안전)Lax
: 기본값, 일부 GET 요청엔 허용None
: 외부 요청에도 허용 (이 경우secure
필수)
실전 예제: CSRF 방어 전체 코드
<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
die('잘못된 접근입니다!');
}
// 실제 삭제 실행
deleteUser($_SESSION['user_id']);
echo "탈퇴가 완료되었습니다.";
exit;
}
?>
<form method="POST">
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
<button type="submit">회원 탈퇴</button>
</form>
주의할 점 ✅
항목 | 설명 |
---|---|
토큰은 세션에 저장 | 각 사용자별로 고유한 토큰 필요 |
토큰은 숨겨서 전송 | <input type="hidden"> 으로만 사용 |
토큰은 GET 방식에 포함하지 않기 | 노출 위험 있음 |
토큰은 1회성 사용 권장 | 요청 후 갱신하면 더 안전함 |
HTTPS + 쿠키 옵션 함께 설정 | CSRF + 세션 탈취 동시 방어 가능 |
마무리 요약 🎯
항목 | 설명 |
---|---|
CSRF란? | 사용자의 신뢰를 악용해 의도치 않은 요청을 수행하는 공격 |
핵심 방어법 | CSRF 토큰 사용, Referer 확인, POST 제한, SameSite 설정 |
가장 효과적인 방법 | CSRF 토큰 + 세션 매칭 |
실무 적용 필수 | 탈퇴, 정보 변경, 결제, 설정 저장 등 중요한 모든 요청에 적용해야 함 |
마무리하며 😊
CSRF는 겉으로는 전혀 이상 없어 보이지만,
이용자의 권한을 몰래 도용해 악의적인 행위를 유도할 수 있는 매우 교묘한 공격이에요.
하지만 오늘 배운 내용들을 제대로 적용하면,
웹 애플리케이션을 CSRF로부터 철벽 방어할 수 있어요!
💡 기억하세요!
“중요한 요청에는 반드시 토큰을, 쿠키엔 반드시 제한을!”
다음 시간에는 파일 업로드 보안과 경로 탐색(Directory Traversal) 공격 방지에 대해 이어서 설명드릴게요~
오늘도 보안 잘 챙기면서 안전하고 똑똑한 개발자 되시길 바랍니다! 💻🛡️🔥