모든 웹 애플리케이션은 해커의 악의적인 공격(XSS, CSRF, SQL Injection 등)에 노출되어 있습니다. Slim 프레임워크의 CSRF Guard 미들웨어를 적용하여 폼(Form) 위조 공격을 완벽히 차단하고, PHP의 내장 함수를 활용해 사용자가 입력한 모든 데이터를 서버에 저장하기 전 안전하게 정화(Sanitization)하는 핵심 보안 계층(Security Layer) 구축 방법을 배웁니다.
1. XSS 공격과 데이터 필터링(Sanitization)
게시판이나 댓글 창에 해커가 악성 자바스크립트(<script>)를 몰래 입력하여, 다른 사용자의 브라우저에서 실행되게 만드는 공격을 XSS(Cross-Site Scripting)라고 합니다. 백엔드 개발자의 가장 기본 철칙은 "클라이언트가 보낸 모든 입력을 절대 신뢰하지 않고 무조건 필터링한다"는 것입니다.
방어 기법
PHP 내장 함수 및 동작 원리
HTML 태그 무효화
htmlspecialchars($input, ENT_QUOTES, 'UTF-8') < 기호를 < 로 변환하여, DB에 저장된 후 화면에 출력될 때 브라우저가 실행 가능한 태그가 아닌 단순 텍스트로 인식하게 만듭니다.
모든 태그 강제 삭제
strip_tags($input) 문자열 내에 포함된 모든 HTML, PHP 태그를 흔적도 없이 완전히 제거해 버립니다.
타입/정규식 필터링
filter_var($input, FILTER_SANITIZE_EMAIL) 이메일이나 숫자 등 기대하는 특정 포맷에 맞지 않는 불필요한 문자를 걸러냅니다.
2. CSRF(Cross-Site Request Forgery) 방어
CSRF는 해커가 사용자의 로그인 권한(세션/쿠키)을 훔쳐, 사용자의 의도와 상관없이 몰래 송금이나 회원 탈퇴 등의 치명적인 요청을 보내도록 위조하는 해킹 기법입니다. 이를 원천 차단하기 위해 서버는 폼(Form)을 그릴 때마다 일회용 난수 보안 토큰을 발행하고, 폼이 전송될 때 이 토큰이 일치하는지 미들웨어 단에서 엄격하게 검사해야 합니다.
index.php (Security Settings)
<?php
// 1. 패키지 설치: composer require slim/csrf
use Slim\Csrf\Guard;
// 2. 세션 시작 (토큰을 서버 메모리에 저장하기 위해 필수)
session_start();
// 3. CSRF Guard 객체 생성 및 전역 미들웨어로 앱에 장착
$responseFactory = $app->getResponseFactory();
$csrf = new Guard($responseFactory);
$app->add($csrf);
// ----------------------------------------
// GET 라우트: CSRF 토큰을 생성하여 뷰(View)에 내려줌
// ----------------------------------------
$app->get('/form', function ($request, $response) use ($csrf) {
// 보안 토큰 이름과 실제 난수값 획득
$nameKey = $csrf->getTokenNameKey();
$valueKey = $csrf->getTokenValueKey();
$name = $request->getAttribute($nameKey);
$value = $request->getAttribute($valueKey);
// HTML Form 안에 hidden 필드로 토큰을 몰래 심어둡니다.
$html = "
<form method='POST' action='/submit'>
<input type='hidden' name='$nameKey' value='$name'>
<input type='hidden' name='$valueKey' value='$value'>
<input type='text' name='message'>
<button type='submit'>보안 전송</button>
</form>";
$response->getBody()->write($html);
return $response;
});
// ----------------------------------------
// POST 라우트: 폼 처리 (미들웨어가 방어벽 역할을 먼저 수행함)
// ----------------------------------------
$app->post('/submit', function ($request, $response) {
// 💡 이 비즈니스 로직까지 도달했다는 것은 CSRF 토큰 검사를 무사히 통과했다는 뜻입니다!
$data = $request->getParsedBody();
// XSS 방지를 위한 데이터 Sanitization 적용
$cleanMessage = htmlspecialchars($data['message'] ?? '', ENT_QUOTES, 'UTF-8');
// DB 저장...
$response->getBody()->write("안전하게 처리 및 저장됨: " . $cleanMessage);
return $response;
});
?>
[Success] 데이터 변환 및 저장 완료: <script>alert('쿠키 탈취!');</script>
[Info] 타 사이트에서 위조된 POST 요청 전송 시도 수신 (토큰 누락)
> CSRF Middleware: 토큰 검증 중...
[Error] ⛔ Failed CSRF check! 토큰이 없거나 유효하지 않습니다.
[Error] HTTP 400 Bad Request 리턴 (비즈니스 로직 접근 원천 차단)
💡 JWT 인증 API 서버와 CSRF 방어의 상관관계
이전 챕터에서 배운 브라우저가 자동으로 첨부하지 않는 JWT(Bearer Token) 전용 API 서버라면 구조적으로 CSRF 공격 자체가 불가능합니다. 하지만 일반적인 세션/쿠키 기반의 인증을 혼용하거나 SSR 웹사이트를 함께 운영한다면, 이 CSRF 방어 미들웨어는 무조건 필수적으로 적용해야 합니다.
웹 보안 방어 로그 검증
위의 백엔드 보안 로그 목업에서는 두 가지 방어 시나리오를 보여줍니다. 첫 번째는 악성 스크립트 페이로드가 들어왔을 때, htmlspecialchars()를 통해 브라우저가 실행할 수 없는 단순 텍스트 문자열(<script>)로 무력화(Sanitization)되어 안전하게 DB에 저장되는 모습입니다. 두 번째는 해커가 타 사이트에서 보안 토큰을 누락한 위조 폼을 전송했을 때, 미들웨어 단계에서 즉각적으로 라우터 진입을 차단(400 Bad Request)하는 CSRF 방어선 동작을 보여줍니다.