XSS는 Cross-Site Scripting의 약자로, 공격자가 피해자의 브라우저에서 악성 JavaScript를 실행하게 만드는 공격입니다. 예를 들어 사용자가 입력한 댓글을 escaping 없이 innerHTML로 넣으면 script나 event handler가 실행될 수 있습니다. 공격이 성공하면 token 탈취, 사용자 행동 대리 수행, 페이지 변조가 가능해질 수 있습니다.
방어는 기본적으로 신뢰할 수 없는 입력을 그대로 HTML로 렌더링하지 않고, context에 맞게 escaping하거나 sanitization하는 것입니다. 추가로 CSP, HttpOnly cookie, framework의 안전한 렌더링 규칙을 함께 사용합니다.
꼬리질문
조금 더 깊게 물어본다면
답변 뒤에 이어질 수 있는 질문들을 하나씩 열어볼 수 있어요.
stored XSS와 reflected XSS는 어떻게 다른가요?
stored XSS는 악성 payload가 서버나 DB에 저장되어 여러 사용자에게 전달되는 형태입니다. reflected XSS는 URL query 같은 입력이 응답에 바로 반사되어 실행되는 형태입니다.
stored XSS는 영향 범위가 넓어질 수 있어 특히 위험합니다.
React를 쓰면 XSS가 완전히 막히나요?
아닙니다. 기본 text 렌더링은 escape되어 안전한 편이지만, dangerouslySetInnerHTML, 외부 HTML renderer, URL 처리, third-party script 등에서 여전히 위험이 있습니다.
프레임워크가 기본 안전장치를 제공해도 개발자가 우회하면 책임이 생깁니다.
HttpOnly cookie는 XSS를 막나요?
XSS 실행 자체를 막지는 못합니다. 다만 악성 script가 cookie 값을 직접 읽지 못하게 해 token 탈취 피해를 줄일 수 있습니다.
XSS 방어와 피해 완화 수단을 구분해서 설명해야 합니다.
CSP는 어떤 역할을 하나요?
Content Security Policy는 어떤 script source를 허용할지, inline script를 막을지 등을 브라우저에 알려주는 정책입니다. XSS payload가 실행되는 것을 줄이는 방어층이 될 수 있습니다.
다만 CSP 하나만 믿기보다 escaping/sanitization과 함께 적용해야 합니다.
부가 설명
container.innerHTML = userInput;
userInput이 신뢰할 수 없는 값이면 위험할 수 있습니다.
<div>{userInput}</div>
React는 기본적으로 text interpolation을 escape하므로 이 경우 script로 실행되지 않습니다. 다만 dangerouslySetInnerHTML을 쓰면 직접 책임져야 합니다.
XSS는 입력 검증만으로 끝나는 문제가 아닙니다. 데이터가 들어오는 시점보다 “어떤 context에 출력되는지”가 더 중요할 때가 많습니다. HTML 본문, attribute, URL, script context마다 안전한 처리 방식이 다릅니다.
XSS는 stored XSS, reflected XSS, DOM-based XSS로 나누어 볼 수 있습니다.
한 줄 정리
XSS는 신뢰할 수 없는 값이 브라우저에서 script로 실행되는 문제이고, 출력 context에 맞는 escaping과 방어층이 필요합니다.