PHP에서 CSRF(크로스 사이트 요청 위조, Cross-Site Request Forgery) 공격 방지는 웹 애플리케이션의 보안을 강화하기 위해 필수적인 작업입니다. CSRF 공격은 공격자가 사용자의 인증된 세션을 악용하여 서버에 부적절한 요청을 전송하는 행위입니다.
1. CSRF 공격 개요
1.1 CSRF란?
- 공격자가 피해자 대신 인증된 세션에서 요청을 서버로 전송하는 공격.
- 사용자가 로그인한 상태에서 악성 스크립트를 통해 원치 않는 작업을 수행하게 만듦.
1.2 동작 방식
(1) 사용자가 신뢰할 수 있는 사이트에 로그인하여 세션을 유지.
(2) 공격자가 피해자를 악성 링크로 유도하거나 스크립트를 실행.
(3) 피해자의 브라우저가 인증된 세션을 통해 악성 요청을 서버에 전송.
(4) 서버는 요청이 인증된 사용자로부터 온 것으로 인식하고 처리.
2. CSRF 방지 방법
2.1 CSRF 토큰 사용
(1) 고유한 토큰 생성: 서버는 사용자의 세션에 고유한 CSRF 토큰을 생성 및 저장.
(2) 토큰 검증: 클라이언트가 요청 시 이 토큰을 함께 제출하도록 요구.
(3) 비교 및 검증: 서버는 요청의 토큰이 세션에 저장된 토큰과 일치하는지 확인.
2.2 사용자 인증 강화
- CSRF 방지는 주로 POST 요청에 적용되지만, GET 요청에서도 검증이 필요할 수 있음.
- 중요한 작업(데이터 변경, 삭제 등)은 CSRF 토큰을 반드시 요구.
3. 실무 코드
3.1 CSRF 토큰 생성 및 저장
csrf.php
<?php
session_start();
/**
* CSRF 토큰 생성 및 세션 저장
* @return string 생성된 CSRF 토큰
*/
function generateCsrfToken(): string {
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
/**
* CSRF 토큰 검증
* @param string $token 요청에 포함된 CSRF 토큰
* @return bool 검증 결과
*/
function validateCsrfToken(string $token): bool {
return hash_equals($_SESSION['csrf_token'] ?? '', $token);
}
3.2 HTML 폼에 CSRF 토큰 추가
form.php
<?php
require 'csrf.php';
// CSRF 토큰 생성
$csrfToken = generateCsrfToken();
?>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>CSRF 방지 폼</title>
</head>
<body>
<h1>CSRF 방지 폼</h1>
<form action="process.php" method="POST">
<label for="data">데이터 입력:</label>
<input type="text" id="data" name="data" required>
<!-- CSRF 토큰 숨김 필드 -->
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrfToken) ?>">
<button type="submit">전송</button>
</form>
</body>
</html>
3.3 CSRF 토큰 검증 및 데이터 처리
process.php
<?php
require 'csrf.php';
session_start();
// 입력 데이터와 CSRF 토큰 가져오기
$data = $_POST['data'] ?? '';
$csrfToken = $_POST['csrf_token'] ?? '';
// CSRF 토큰 검증
if (!validateCsrfToken($csrfToken)) {
die("CSRF 검증 실패: 요청이 허용되지 않았습니다.");
}
// 데이터 처리
echo "데이터 처리 성공: " . htmlspecialchars($data);
3.4 로그아웃 시 세션 초기화
logout.php
<?php
session_start();
session_unset();
session_destroy();
header("Location: form.php");
exit;
4. 작동 원리
(1) 폼 생성 시
- generateCsrfToken()을 호출하여 CSRF 토큰을 생성하고 세션에 저장.
- 생성된 토큰은 폼의 숨겨진 입력 필드에 포함.
(2) 폼 제출 시
- 서버는 요청에서 받은 csrf_token 값을 세션에 저장된 값과 비교.
- 값이 일치하지 않으면 요청을 거부.
5. CSRF 방지 구현 시 고려사항
(1) 토큰 고유성 보장: 토큰은 예측 불가능한 값이어야 함(random_bytes() 사용).
(2) HTTPS 사용: 요청 및 토큰 전송 과정에서 암호화를 보장.
(3) 폼당 고유 토큰: 요청마다 새로운 토큰을 생성하여 재사용 공격 방지.
(4) 세션 시간 관리: 세션 만료 시 토큰도 무효화.
(5) 로그아웃 처리: 로그아웃 시 세션 데이터를 제거하여 토큰 유효성 제거.
6. 결과 예제
(1) 입력 화면 (form.php)
사용자에게 폼이 표시되며 숨겨진 필드에 CSRF 토큰이 포함됨.
<form action="process.php" method="POST">
<input type="text" name="data" required>
<input type="hidden" name="csrf_token" value="abcdef1234567890...">
<button type="submit">전송</button>
</form>
(2) 성공 처리 (process.php)
CSRF 검증 성공 시, 요청 데이터가 안전하게 처리됨.
데이터 처리 성공: 사용자 입력 값
(3) 검증 실패
CSRF 토큰이 없거나 일치하지 않으면 요청이 거부됨.
CSRF 검증 실패: 요청이 허용되지 않았습니다.
7. 요약
(1) CSRF 토큰은 필수: 모든 중요한 POST 요청에 적용.
(2) HTTPS 사용: 토큰 및 요청 데이터 암호화.
(3) 정확한 구현 필요: 세션 관리 및 토큰 검증 절차가 정확해야 함.
(4) 유효한 세션 유지: 사용자의 세션이 안전하게 관리되어야 함.
With ChatGPT
'PHP > 포스팅' 카테고리의 다른 글
[PHP] URL 길이 제한 (0) | 2024.12.27 |
---|---|
[PHP] CSRF 공격 방지 데이터 베이스 활용 (0) | 2024.12.26 |
[PHP] XSS 방지 (0) | 2024.12.26 |
[PHP] GET 방식 폼 양식의 데이터 처리 (0) | 2024.12.26 |
[PHP] POST 방식 폼 양식의 데이터 처리 (0) | 2024.12.25 |