Post

XSS란 무엇이며, 어떻게 방어할 수 있을까?

🔍 XSS란 무엇인가?

크로스 사이트 스크립팅(Cross-Site Scripting, 이하 XSS)은 웹 보안 취약점 중 하나로, 공격자가 사용자의 웹 브라우저에 악의적인 스크립트를 주입할 수 있게 하는 공격 방식입니다.

이 취약점은 웹 애플리케이션에서 사용자 입력을 적절히 검증하거나 이스케이프 처리하지 않을 때 발생합니다. XSS 공격은 사용자의 세션 토큰, 쿠키, 개인 정보 등을 탈취하거나 사용자를 대신하여 특정 행위를 수행하게 만드는 등 다양한 형태로 이루어질 수 있습니다.

🔍 XSS는 왜 등장했는가?

XSS 취약점은 웹 애플리케이션의 발전과 함께 등장했습니다. 초기 웹 사이트들은 주로 정적인 정보를 제공하는 데 초점을 맞췄지만, 시간이 지나면서 사용자 상호작용과 개인화된 콘텐츠의 필요성이 증가했습니다. 이러한 변화로 사용자 입력을 받아서 처리하는 기능이 필수가 되었고, 이 과정에서 입력값에 대한 충분한 검증과 적절한 처리가 이루어지지 않아 XSS와 같은 취약점이 발생하게 되었습니다.

🔍 XSS 공격의 작동 원리

✏️ 비 지속적 기법 (non-persistent)

사용자가 특정한 링크를 클릭할 때 발생합니다. 링크에는 악의적인 스크립트가 포함되어 있으며, 사용자가 링크를 클릭하면 웹 애플리케이션은 이 스크립트를 웹 페이지에 반영해 사용자의 브라우저에서 실행합니다.

1
http://example.com/?query=<script>alert('악의적인 스크립트')</script>

✏️ 지속적 기법 (persistent)

악의적인 스크립트가 웹 서버에 저장되는 경우입니다. 예를 들어, 사용자가 댓글, 게시물, 사용자 프로필 등에 스크립트를 삽입하면, 이 스크립트는 다른 사용자들이 해당 콘텐츠를 볼 때마다 실행됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html>
<head>
    <title>XSS 공격 시뮬레이션</title>
</head>
<body>
    <h1>댓글 섹션</h1>
    <div id="comments">
        <!-- 사용자가 입력한 댓글 -->
        <p>사용자 댓글: 
	        <script>alert('XSS 공격입니다!');</script>
		</p>
    </div>
</body>
</html>

✏️ DOM based XSS

DOM 기반 XSS는 웹 애플리케이션의 클라이언트 측 코드에서 발생합니다. 이 경우, 악의적인 스크립트는 페이지 자체에는 저장되지 않지만, 페이지의 DOM을 조작하여 실행됩니다.

1
2
3
// URL의 파라미터를 통해 입력된 값을 페이지에 반영
const input = window.location.href.split('input=')[1];
document.getElementById('output').innerHTML = decodeURIComponent(input);

🔍 XSS 공격 방지 방법

✏️ 이스케이핑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!DOCTYPE html>
<html>
<head>
    <title>XSS 방지 예시</title>
</head>
<body>
    <form id="myForm">
        <label for="userInput">입력:</label>
        <input type="text" id="userInput" name="userInput">
        <button type="submit">제출</button>
    </form>
    <div id="result"></div>
<script>
	document.getElementById('myForm').addEventListener('submit', function(event) {
	    event.preventDefault();
	
	    // 사용자 입력 값 가져오기
	    var userInput = document.getElementById('userInput').value;
	
	    // XSS 방지를 위한 이스케이핑
	    var safeInput = escapeHtml(userInput);
	
	    // 결과를 안전하게 페이지에 표시
	    document.getElementById('result').innerText = safeInput;
	});
	
	function escapeHtml(unsafe) {
	    return unsafe
	             .replace(/&/g, "&amp;")
	             .replace(/</g, "&lt;")
	             .replace(/>/g, "&gt;")
	             .replace(/"/g, "&quot;")
	             .replace(/'/g, "&#039;");
	}
</script>
</body>
</html>

✏️ 사용자 입력 검증

1
2
3
4
function validateInput(input) {
    let pattern = /<script.*?>.*?<\/script>/gi;
    return input.replace(pattern, '');
}

✏️ CSP 헤더 설정

CSP(Content-Security-Policy) 헤더는 웹 서버가 클라이언트에 보내는 HTTP 응답 헤더 중 하나로, 웹 페이지에서 사용할 수 있는 리소스의 종류를 제한합니다.

1
Content-Security-Policy: <policy-directive>; <policy-directive>

다음은 자신의 주소와 google.com의 스크립트 리소스만 허용하는 것을 의미한다.

1
Content-Security-Policy: script-src 'self' *.google.com;

✏️ Vue, React와 같은 프레임워크 이용하기

기본적으로 Vue, React, Angular와 같은 웹 프레임워크는 일부 XSS 공격을 방지하는 메커니즘을 제공합니다.

자동 이스케이프

1
2
3
4
5
<h1></h1>
// 값이 '<script>alert("hi")</script>' 일 때

// 다음과 같이 이스케이프 된다.
&lt;script&gt;alert(&quot;hi&quot;)&lt;/script&gt;

🔍 참고

위키백과 - 사이트 간 스크립팅
Cloudflare
CSP란?
Vue Guide

This post is licensed under CC BY 4.0 by the author.

© bear-su. Some rights reserved.