🛡️ Express.js (API Only) XSS 방지 대책
1. 📝 입력 데이터 정제 (Input Sanitization)
사용자 입력(JSON, 쿼리 파라미터 등)을 데이터베이스에 저장하거나 응답으로 보내기 전에 악성 HTML이나 스크립트 코드를 제거합니다.
✅ 샘플 코드: dompurify와 jsdom을 사용한 정제
Express 환경에서는 브라우저 환경에서 사용되는 **dompurify**를 서버 측에서 실행하기 위해 **jsdom**과 함께 사용하거나, **sanitize-html**과 같은 라이브러리를 사용합니다. 여기서는 널리 사용되는 **sanitize-html**을 사용합니다.
Bash
# 💡 라이브러리 설치
npm install sanitize-html express
JavaScript
const express = require('express');
const sanitizeHtml = require('sanitize-html');
const app = express();
app.use(express.json()); // JSON 요청 본문을 파싱
// API 서버이므로 HTML 태그를 허용하지 않는 것이 가장 안전합니다.
const sanitizeOptions = {
allowedTags: [], // 허용 태그 없음
allowedAttributes: {} // 허용 속성 없음
};
app.post('/api/posts', (req, res) => {
const rawContent = req.body.content;
// ❌ 정제 없이 직접 사용 (위험!)
// const content = rawContent;
// ✅ sanitize-html을 사용하여 모든 HTML 태그를 제거하고 안전한 텍스트로 만듦
const sanitizedContent = sanitizeHtml(rawContent, sanitizeOptions);
// DB 저장 로직: sanitizedContent를 저장
// ...
res.status(201).json({
message: "Post created successfully",
content: sanitizedContent
});
});
app.listen(3000, () => console.log('Server running on port 3000'));
설명: sanitize-html을 사용하여 사용자 입력에서 모든 HTML 태그를 제거합니다. 이로써 프론트엔드에서 데이터를 렌더링할 때 <script> 같은 태그가 실행되는 것을 원천적으로 차단합니다.
2. 🛡️ 보안 HTTP 헤더 설정 (Security Headers)
API 응답에 보안 헤더를 추가하여, 설령 공격 코드가 삽입되더라도 브라우저의 보안 정책을 통해 실행을 억제합니다.
✅ 샘플 코드: helmet 미들웨어를 사용한 자동 설정
Express에서 보안 헤더를 쉽게 설정하기 위해 helmet 라이브웨어를 사용하는 것이 업계 표준입니다.
Bash
# 💡 라이브러리 설치
npm install helmet
JavaScript
const express = require('express');
const helmet = require('helmet');
const app = express();
// 1. ✅ Helmet 미들웨어를 사용하여 기본적인 보안 헤더를 설정합니다.
// X-Content-Type-Options, X-Frame-Options 등 여러 헤더를 자동으로 추가합니다.
app.use(helmet());
// 2. Content Security Policy (CSP) 설정
// API 서버이므로 'self'로 엄격하게 설정하는 것이 좋습니다.
app.use(
helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
objectSrc: ["'none'"], // <object>, <embed> 태그 사용 금지
scriptSrc: ["'self'"] // 스크립트 로딩을 현재 도메인으로 제한
},
})
);
app.get('/api/users', (req, res) => {
// 이 응답에는 위에 설정된 강력한 보안 헤더가 자동으로 포함됩니다.
res.json({ users: [{ id: 1, name: 'Alice' }] });
});
app.listen(3000, () => console.log('Server running with Helmet on port 3000'));
설명:
- helmet(): Flask에서 수동으로 추가했던 X-Content-Type-Options: nosniff, X-Frame-Options: DENY 등 다수의 보안 헤더를 한 줄로 적용합니다.
- helmet.contentSecurityPolicy(...): CSP는 가장 중요한 방어막입니다. defaultSrc: ["'self'"]를 통해 브라우저는 현재 도메인에서 로드된 리소스만 신뢰하게 되어 외부에서 주입된 악성 스크립트 실행을 차단합니다.
3. 🍪 HttpOnly 쿠키 사용
인증 및 세션 관리에 사용되는 쿠키는 XSS 공격을 통해 탈취되는 것을 막기 위해 HttpOnly 옵션을 설정해야 합니다.
✅ 샘플 코드: 쿠키 설정 시 httpOnly: true 옵션 사용
Express에서는 res.cookie() 메서드를 사용할 때 옵션을 지정할 수 있습니다.
JavaScript
// Express에서는 'cookie-parser' 라이브러리가 세션 관리에 사용되기도 합니다.
app.post('/api/login', (req, res) => {
// ... 인증 로직 ...
const sessionToken = 'secure_random_token_value';
// ✅ HttpOnly 설정: 클라이언트 JavaScript가 쿠키에 접근 불가능
res.cookie('session_token', sessionToken, {
httpOnly: true, // XSS를 통한 쿠키 탈취 방지
secure: true, // HTTPS 환경에서만 전송
sameSite: 'Lax', // CSRF 방지에도 도움
maxAge: 3600000 // 1시간 유효
});
res.json({ message: "Login successful" });
});
이 세 가지 방법을 통해 Express API 서버는 데이터 정제, 강력한 보안 헤더, 안전한 세션 관리를 통해 XSS 공격을 효과적으로 방어할 수 있습니다.
'Web Security' 카테고리의 다른 글
| CSRF(일부XSS포함) 방지책 (ReactJS + Flask) (0) | 2025.12.02 |
|---|---|
| XSS 방지책 (Flask) (0) | 2025.12.02 |
| XSS 방지책 (ReactJS) (0) | 2025.12.02 |
| CSRF (Cross-Site Request Forgery) attack (0) | 2025.12.02 |
| 크로스 사이트 스크립팅 (Cross-Site Scripting, XSS) (0) | 2025.11.30 |