CSRF 토큰 구현
1. 토큰 생성 및 저장
function generateCSRFToken() {
$token = bin2hex(random_bytes(32));
$_SESSION['csrf_token'] = $token;
return $token;
}
2. 폼에 토큰 추가
<form method="POST" action="/process">
<input type="hidden" name="csrf_token" value="<?php echo generateCSRFToken(); ?>">
<input type="text" name="username">
<button type="submit">Submit</button>
</form>
3. 토큰 검증
function validateCSRFToken($token) {
return isset($_SESSION['csrf_token']) &&
hash_equals($_SESSION['csrf_token'], $token);
}
CSRF 보호 클래스
class CSRFProtection {
public static function generateToken() {
$token = bin2hex(random_bytes(32));
$_SESSION['csrf_token'] = $token;
return $token;
}
public static function verifyToken($token) {
return isset($_SESSION['csrf_token']) &&
hash_equals($_SESSION['csrf_token'], $token);
}
public static function getTokenField() {
$token = self::generateToken();
return '<input type="hidden" name="csrf_token" value="' . $token . '">';
}
}
미들웨어 구현
class CSRFMiddleware {
public function handle($request) {
if ($this->isPostRequest()) {
if (!$this->validateToken()) {
throw new Exception('CSRF token validation failed');
}
}
}
private function isPostRequest() {
return $_SERVER['REQUEST_METHOD'] === 'POST';
}
private function validateToken() {
return isset($_POST['csrf_token']) &&
validateCSRFToken($_POST['csrf_token']);
}
}
보안 헤더 설정
실제 구현 예시
// 폼 처리
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (validateCSRFToken($_POST['csrf_token'])) {
// 폼 처리 로직
processForm($_POST);
} else {
// 토큰 검증 실패
throw new Exception('Invalid CSRF token');
}
}
API 요청 보호
// API 요청에 CSRF 토큰 추가
fetch('/api/data', {
method: 'POST',
headers: {
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content
},
body: formData
});
모범 사례
- 모든 POST 요청에 CSRF 토큰 사용
- 토큰 유효성 검사
- 세션별 고유 토큰 생성
- 안전한 토큰 생성 방식 사용
- 정기적인 토큰 갱신