🛡️
EPISODE 01
Stored/Reflected/DOM XSS · innerHTML · DOMPurify · CSP
XSS 방어
XSS의 3가지 유형, innerHTML의 위험성과 textContent로의 안전한 대안, 서버측 이스케이프, DOMPurify로 부분 HTML 허용, 그리고 CSP 헤더로 추가 보호층을 익힙니다.
XSS보안CSPDOMPurify
소요 시간
⏱ 45분
난이도
📊 중급
선수 조건
🎯 a11y-04
결과물
사용자 입력을 안전하게 렌더링하는 폼·댓글 페이지
이 강의에서 배우는 것
- 1Stored / Reflected / DOM XSS 의 차이를 안다
- 2innerHTML 대신 textContent를 사용한다
- 3DOMPurify로 마크다운/리치텍스트를 안전하게 처리한다
- 4CSP 헤더와 helmet으로 추가 보호층을 만든다
1. XSS란
공격자가 웹 페이지에 악성 스크립트를 삽입해 다른 사용자 브라우저에서 실행시키는 공격. 쿠키/세션 탈취, 키로거, 피싱 리다이렉트 등.
2. XSS 3가지 유형
Stored XSS — DB에 저장
text
[공격자] 댓글에 <script>document.cookie를 전송</script>
[서버] DB에 저장
[피해자] 페이지 방문 시 자동 실행Reflected XSS — URL에 반사
text
악성 URL: https://bank.com/search?q=<script>...</script>
공격자가 피해자에게 이메일로 전송 → 서버 응답에 그대로 반사 → 실행DOM XSS — 클라이언트 JS
javascript
// 취약: URL 해시를 그대로 innerHTML
const hash = location.hash.substring(1);
document.getElementById('output').innerHTML = hash;
// 공격: https://site.com/#<img src=x onerror=악성코드>3. innerHTML의 위험성
javascript
// ✗ 절대 금지
element.innerHTML = userInput;
// 공격자: '<img src=x onerror="document.cookie 전송">' → XSS!
// ✓ textContent (HTML 태그를 텍스트로)
element.textContent = userInput;
// '<script>...' 가 그대로 화면에 텍스트로 표시
// ✓ createElement + textContent
const p = document.createElement('p');
p.textContent = userInput;
container.appendChild(p);4. 서버측 이스케이프
javascript
function escapeHtml(str) {
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
// <script>alert(1)</script>
// → <script>alert(1)</script>
// → 화면에 텍스트로만 표시5. DOMPurify
마크다운 에디터처럼 일부 HTML 태그는 허용해야 할 때.
html
<script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.6/purify.min.js"></script>javascript
const dirty = '<img src=x onerror=alert(1)> <b>안전한 텍스트</b>';
const clean = DOMPurify.sanitize(dirty);
// 결과: " <b>안전한 텍스트</b>" ← onerror 제거, 안전한 태그 유지
element.innerHTML = DOMPurify.sanitize(userInput);6. CSP (Content-Security-Policy)
javascript
app.use((req, res, next) => {
res.setHeader('Content-Security-Policy',
"default-src 'self'; " +
"script-src 'self'; " +
"style-src 'self' 'unsafe-inline';"
);
next();
});
// 권장: helmet
const helmet = require('helmet');
app.use(helmet());CSP가 있으면 <script>alert(1)</script> 같은 인라인 스크립트가 차단됩니다.