고급 PHP 프로그래밍 – 웹 보안 – 2 – 크로스 사이트 요청 위조(CSRF) 방지

고급 PHP 프로그래밍 - 웹 보안 - 2 - 크로스 사이트 요청 위조(CSRF) 방지
고급 PHP 프로그래밍 – 웹 보안 – 2 – 크로스 사이트 요청 위조(CSRF) 방지

고급 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) 공격 방지에 대해 이어서 설명드릴게요~

오늘도 보안 잘 챙기면서 안전하고 똑똑한 개발자 되시길 바랍니다! 💻🛡️🔥

답글 남기기