PHP/포스팅

[PHP] XSS 방지

짜집퍼박사(짜박) 2024. 12. 26. 00:17

PHP에서 XSS(Cross-Site Scripting) 공격을 방지하기 위해 다음 사항을 고려해야 합니다.

 

1. XSS란?

XSS는 공격자가 악성 스크립트를 웹 페이지에 삽입하여 다른 사용자에게 실행시키는 공격 기법입니다.

 

공격 시나리오

- 스토어드 XSS: 공격 스크립트를 데이터베이스에 저장하여 여러 사용자에게 실행.

- 리플렉티드 XSS: 공격 스크립트를 요청 URL 등에 포함하여 즉시 실행.

- DOM 기반 XSS: 클라이언트 측에서 DOM 조작을 통해 발생.

 

2. XSS 방지 원칙

2.1 입력 데이터 검증

- 모든 입력 데이터를 신뢰하지 않는다.

- 필요하지 않은 HTML, 스크립트 입력을 차단.

 

2.2 출력 시 필터링

- HTML, URL, JavaScript, CSS 등 컨텍스트에 맞는 필터링 적용

-- HTML: htmlspecialchars() 또는 htmlentities()

-- URL: urlencode() 또는 rawurlencode()

-- JavaScript: JSON 형태로 인코딩

 

2.3 콘텐츠 보안 정책 (CSP)

브라우저에서 실행 가능한 스크립트를 제한.

 

3. PHP에서 XSS 방지 실무 소스

3.1 프로젝트 구조

(1) index.php - 사용자 입력 폼

(2) process.php - 데이터 처리 및 결과 출력

(3) utils.php - 보조 함수 제공

 

3.2 입력 폼 (index.php)

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>XSS 방지 데모</title>
</head>
<body>
    <h1>XSS 방지 데모</h1>
    <form action="process.php" method="POST">
        <label for="username">사용자 이름:</label>
        <input type="text" id="username" name="username" required>
        <br><br>
        <label for="comment">댓글:</label>
        <textarea id="comment" name="comment" rows="5" required></textarea>
        <br><br>
        <button type="submit">전송</button>
    </form>
</body>
</html>

 

3.3 데이터 처리 (process.php)

<?php
require 'utils.php';

// 데이터 수신
$username = $_POST['username'] ?? '';
$comment = $_POST['comment'] ?? '';

// HTML 엔티티 처리 (XSS 방지)
$username = escapeHtml($username);
$comment = escapeHtml($comment);

// 결과 출력
?>
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>처리 결과</title>
</head>
<body>
    <h1>처리 결과</h1>
    <p>사용자 이름: <?= $username ?></p>
    <p>댓글:</p>
    <pre><?= $comment ?></pre>
    <br>
    <a href="index.php">돌아가기</a>
</body>
</html>

 

3.4 보조 함수 (utils.php)

<?php

/**
 * HTML 특수문자를 엔티티로 변환
 * @param string $string 사용자 입력 데이터
 * @return string 변환된 문자열
 */
function escapeHtml(string $string): string {
    return htmlspecialchars($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}

/**
 * URL 인코딩 (출력 시 URL 컨텍스트에서 사용)
 * @param string $string URL 파라미터 값
 * @return string 인코딩된 URL
 */
function escapeUrl(string $string): string {
    return rawurlencode($string);
}

/**
 * JSON 출력용 이스케이프
 * @param string $string JavaScript 출력에 사용할 데이터
 * @return string JSON 안전하게 변환된 문자열
 */
function escapeJs(string $string): string {
    return json_encode($string, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
}

 

4. 보안 체크리스트

4.1 XSS 방지에 꼭 해야 할 것

(1) 입력 검증: 허용된 데이터만 입력 가능하도록 제한.

(2) 출력 컨텍스트에 따른 필터링

- HTML 컨텍스트: htmlspecialchars()

- URL 컨텍스트: rawurlencode()

- JavaScript 컨텍스트: json_encode()

(3) HTTP 응답 헤더 설정

Content-Security-Policy로 인라인 스크립트 제한.

header("Content-Security-Policy: default-src 'self'; script-src 'self';");

 

5. 실행 결과

(1) 입력 예 (index.php)

- 사용자 이름: <script>alert('XSS');</script>

- 댓글: <b>Hello, World!</b>

 

(2) 출력 결과 (process.php)

<p>사용자 이름: &lt;script&gt;alert('XSS');&lt;/script&gt;</p>
<p>댓글:</p>
<pre>&lt;b&gt;Hello, World!&lt;/b&gt;</pre>

<script> 및 <b> 태그가 그대로 텍스트로 출력되며, 스크립트가 실행되지 않습니다.

 

6. 확장 적용

(1) 데이터베이스 연동

- 입력값을 저장하기 전에 필터링 및 검증.

- 데이터 조회 후 출력 시 컨텍스트에 맞는 필터링 적용.

(2) 로그 데이터 처리

로그 파일이나 API 응답에 삽입 시에도 동일한 원칙 적용.

(3) 템플릿 엔진

Twig 또는 Blade와 같은 템플릿 엔진은 기본적으로 출력 시 HTML 특수문자를 이스케이프 처리.

 

7. 요약

- 핵심은 입력 검증과 출력 필터링이다.

- XSS 방지는 단순한 엔코딩 이상의 고려가 필요하며, 웹 애플리케이션의 모든 단계에서 구현해야 한다.

 

With ChatGPT