Security 클래스
CI4의 esc(), sanitizeFilename(), CSRF 보호 등 내장 보안 기능으로 XSS 및 파일명 인젝션을 방어합니다.
입력 새니타이즈 비교 — esc() vs strip_tags() vs htmlspecialchars() vs sanitizeFilename()
| 함수 | 결과 |
|---|
왼쪽에 문자열을 입력하고 버튼을 누르세요.
XSS 패턴 → esc() 처리 결과 시각적 비교
원본 입력 (위험!)
esc($input, 'html') — 안전
esc($input, 'js') — JS 컨텍스트
XSS 페이로드를 입력하면
esc() 처리 전/후를 비교할 수 있습니다.
esc() — 컨텍스트별 이스케이프
$input = '<script>alert("xss")</script>';
// HTML 컨텍스트 (기본값)
esc($input); // <script>...
esc($input, 'html'); // <script>...
// HTML 속성 컨텍스트
// <input value="<?= esc($val, 'attr') ?>">
esc($input, 'attr');
// JavaScript 컨텍스트
// var x = '<?= esc($val, 'js') ?>';
esc($input, 'js');
// URL 컨텍스트
// <a href="<?= esc($url, 'url') ?>">
esc($input, 'url');
// CSS 컨텍스트
esc($input, 'css');
주의:
esc()는 출력 시 이스케이프합니다.
DB 저장 전에 적용하면 이중 인코딩이 발생합니다.
항상 출력 직전에 사용하세요.
sanitizeFilename() — 파일명 보안
$security = \Config\Services::security();
// 경로 탐색 공격 방어
$filename = '../../../etc/passwd';
$safe = $security->sanitizeFilename($filename);
// 결과: 'etcpasswd'
// 특수문자 제거
$filename = 'my file <script>.php';
$safe = $security->sanitizeFilename($filename);
// 결과: 'my file script.php'
// 파일 업로드 시 실제 사용 예
public function upload()
{
$file = $this->request->getFile('upload');
$name = $security->sanitizeFilename(
$file->getClientName()
);
$file->move(WRITEPATH . 'uploads', $name);
}
함수별 특성 비교
| 함수 | 용도 | 특징 | 권장 컨텍스트 |
|---|---|---|---|
esc($v, 'html') |
HTML 출력 | <>&"' 변환 |
HTML 본문 |
esc($v, 'attr') |
HTML 속성 | 속성 값 내 특수문자 변환 | 태그 속성값 |
esc($v, 'js') |
JS 인라인 | JS 특수문자 이스케이프 | script 태그 내 |
esc($v, 'url') |
URL | URL 인코딩 | href, src 속성 |
strip_tags($v) |
태그 제거 | HTML 태그 완전 제거 | 평문 저장 |
sanitizeFilename() |
파일명 | 경로 탐색, 특수문자 제거 | 파일 업로드 |
CSRF 활성화 (Config/Filters.php)
// app/Config/Filters.php
public array $globals = [
'before' => [
'csrf', // 전역 CSRF 활성화
],
];
// 특정 라우트만 제외 (예: webhook)
public array $globals = [
'before' => [
'csrf' => ['except' => ['webhook/*']],
],
];
뷰에서 CSRF 토큰 삽입
// HTML 폼 — 히든 필드 자동 생성
<form method="post">
<?= csrf_field() ?>
<!-- <input type="hidden" name="csrf_test_name"
value="abc123..."> -->
...
</form>
// AJAX 요청 — 헤더에 토큰 포함
fetch('/endpoint', {
method: 'POST',
headers: {
'X-CSRF-TOKEN': '<?= csrf_hash() ?>',
},
body: formData
});
CSRF 설정 (Config/Security.php)
// app/Config/Security.php
class Security extends BaseConfig
{
// 토큰 재생성 전략
// 'cookie' : 요청마다 토큰 재생성 (기본값)
// 'session': 세션에 토큰 저장
public string $tokenRandomize = 'cookie';
// CSRF 토큰 이름 (히든 필드 name)
public string $tokenName = 'csrf_test_name';
// CSRF 쿠키 이름
public string $cookieName = 'csrf_cookie_name';
// 토큰 만료 시간 (초, 0=세션과 동일)
public int $expires = 7200;
// SameSite 속성 (Strict/Lax/None/'')
public string $samesite = 'Lax';
}
현재 상태: 이 프로젝트는 학습용이라 CSRF 전역 필터가 비활성화되어 있습니다.
운영 환경에서는 반드시
'csrf' 전역 필터를 활성화하세요.