PHP에서 HTML 출력 시 특수문자를 제대로 처리하지 않으면 XSS 공격에 취약하거나 화면이 깨지는 문제가 발생합니다. 이런 문제들의 주요 원인과 해결책을 살펴보겠습니다.
문제: 사용자 입력을 그대로 출력하여 스크립트 주입 위험
해결책:
// 사용자 입력 안전하게 출력
$userInput = "<script>alert('XSS')</script>";
echo htmlspecialchars($userInput, ENT_QUOTES, 'UTF-8');
// 결과: <script>alert('XSS')</script>
문제: 특수문자 변환 시 인코딩 설정 누락으로 한글 깨짐
해결책:
// UTF-8 인코딩 명시
$text = "안녕하세요 <script>";
echo htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
// 페이지 상단에 인코딩 설정
header('Content-Type: text/html; charset=UTF-8');
문제: 홑따옴표나 쌍따옴표가 변환되지 않아 HTML 속성 오류
해결책:
// 모든 따옴표 변환
$value = 'O\'Reilly "Books"';
echo '<input value="' . htmlspecialchars($value, ENT_QUOTES, 'UTF-8') . '">';
// 결과: <input value="O'Reilly "Books"">
문제: &
가 &amp;
로 중복 변환되는 문제
해결책:
// 중복 변환 방지
$text = "이미 변환된 & 문자";
echo htmlspecialchars($text, ENT_QUOTES, 'UTF-8', false); // double_encode를 false로
문제: 줄바꿈이 HTML에서 제대로 표시되지 않음
해결책:
// 줄바꿈을 <br>로 변환
$text = "첫 번째 줄\n두 번째 줄";
echo nl2br(htmlspecialchars($text, ENT_QUOTES, 'UTF-8'));
// 결과: 첫 번째 줄<br />두 번째 줄
문제: 모든 HTML을 제거하지 않고 특정 태그만 허용
해결책:
// 특정 태그만 허용
function cleanHtml($input) {
$allowed = '<p><br><strong><em><u>';
return strip_tags($input, $allowed);
}
$userContent = "<p>안전한 내용</p><script>위험한 스크립트</script>";
echo cleanHtml($userContent);
// 결과: <p>안전한 내용</p>위험한 스크립트
문제: URL 파라미터에 특수문자가 포함되어 링크 오류
해결책:
// URL 인코딩
$searchQuery = "PHP & MySQL";
$url = "search.php?q=" . urlencode($searchQuery);
echo '<a href="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '">검색</a>';
문제: JSON에 포함된 특수문자로 인한 파싱 오류
해결책:
// 안전한 JSON 출력
$data = [
'message' => '안녕하세요 "사용자"님!',
'script' => '<script>alert("test")</script>'
];
header('Content-Type: application/json; charset=UTF-8');
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_QUOT);
문제: 업로드된 파일명의 특수문자로 인한 보안 위험
해결책:
// 안전한 파일명 생성
function sanitizeFilename($filename) {
$filename = preg_replace('/[^a-zA-Z0-9._-]/', '_', $filename);
return trim($filename, '._-');
}
$uploadedName = "../../../etc/passwd";
$safeName = sanitizeFilename($uploadedName);
echo $safeName; // ___etc_passwd
문제: HTML 특수문자가 포함된 데이터의 저장과 출력
해결책:
// 저장 시에는 원본 그대로, 출력 시에만 변환
// 저장
$content = $_POST['content']; // 원본 그대로 저장
// 출력
function safeOutput($text) {
return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
}
echo safeOutput($content);
문제: 복잡한 HTML 템플릿에서 일관된 특수문자 처리
해결책:
// 간단한 헬퍼 함수
function e($string) {
return htmlspecialchars($string ?? '', ENT_QUOTES, 'UTF-8');
}
// 사용
$title = "제목 <script>";
$content = "내용 & 특수문자";
echo '<h1>' . e($title) . '</h1>';
echo '<p>' . e($content) . '</p>';