xss-prevention について
Web 開発者向けの XSS 対策スキルです。入力のサニタイズ、文脈に応じた出力エンコード、CSP、安全な DOM API を扱い、ユーザーコンテンツや動的 HTML に適用できます。
主な機能
- 01文脈に応じた出力エンコード
- 02許可リストによる HTML サニタイズ
- 03CSP ヘッダーの設定
- 04安全な DOM API の利用
- 05URL プロトコルの検証
活用シーン
- 01ユーザー生成コンテンツの安全な表示
- 02コメントやリッチテキストエディターの保護
- 03検索パラメーターと動的 HTML の処理
- 04URL とスクリプト注入リスクの確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ secondsky/ claude-skills --skill xss-preventionインストール後、Claude Code で/xss-preventionを入力して読み込まれたか確認します。
同梱ファイルreferences/nodejs-advanced.mdreferences/python-sanitization.md
詳細
XSS の防止
概要
入力のサニタイズ、出力のエンコード、Content Security Policy ヘッダー、安全なコーディング手法を通じて、包括的なクロスサイトスクリプティング攻撃対策を実装します。
使用する場面
- ユーザー生成コンテンツの表示
- リッチテキストエディター
- コメントシステム
- 検索機能
- 動的な HTML の生成
- テンプレートのレンダリング
XSS 攻撃の種類
| 種類 | 攻撃経路 | 防御策 |
|---|---|---|
| 反射型 | URL パラメーター | 出力エンコード |
| 格納型 | データベースのコンテンツ | 入力のサニタイズ |
| DOM ベース | クライアント側の JS | 安全な DOM API |
| ミューテーション | HTML パーサーの癖 | 厳格なサニタイズ |
出力エンコード(Node.js)
function encodeHTML(str) {
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
function encodeForAttribute(str) {
return str.replace(/[^\w.-]/g, char =>
`&#x${char.charCodeAt(0).toString(16)};`
);
}
// Usage in templates
app.get('/profile', (req, res) => {
const username = encodeHTML(req.query.name);
res.send(`<h1>Welcome, ${username}</h1>`);
});
DOMPurify によるサニタイズ
import DOMPurify from 'dompurify';
const config = {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'br'],
ALLOWED_ATTR: ['href', 'title'],
ALLOW_DATA_ATTR: false
};
function sanitizeHTML(dirty) {
return DOMPurify.sanitize(dirty, config);
}
// React component
function RichContent({ html }) {
return (
<div dangerouslySetInnerHTML={{ __html: sanitizeHTML(html) }} />
);
}
Content Security Policy
// Express middleware
app.use((req, res, next) => {
const nonce = crypto.randomBytes(16).toString('base64');
res.locals.nonce = nonce;
res.setHeader('Content-Security-Policy', [
"default-src 'self'",
`script-src 'self' 'nonce-${nonce}'`,
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: https:",
"connect-src 'self' https://api.example.com",
"frame-ancestors 'none'",
"base-uri 'self'",
"form-action 'self'"
].join('; '));
next();
});
安全な DOM API
❌ ユーザーが制御する入力に対して、以下の操作は絶対に行わないでください。これらは XSS のシンクであり、信頼できないデータを使って安全に呼び出す方法はありません。
- 入力を
element.innerHTML/element.outerHTMLに代入する - 入力を
eval()に渡す - 入力を
document.write()に渡す - 文字列として
setTimeout/setIntervalに渡す - インラインイベントハンドラーに挿入する(例:
onclick="...")
// SAFE — use these instead
element.textContent = userInput; // Escaped automatically
element.setAttribute('data-id', id); // Safe for attributes
document.createTextNode(userInput); // Creates safe text node
上記の安全なパターン(textContent、setAttribute による属性のエスケープ、DOMPurify.sanitize)だけが、DOM 内でユーザー入力を処理する正しい方法です。
URL の検証
function isSafeURL(url) {
try {
const parsed = new URL(url);
return ['http:', 'https:'].includes(parsed.protocol);
} catch {
return false;
}
}
// Usage
const href = isSafeURL(userURL) ? userURL : '#';
コンテキストに応じたエンコード
コンテキストごとに適切なエンコード方法は異なります。
- HTML エンティティエンコード:テキストコンテンツに最も安全な方法
- 属性のエンコード:HTML 属性向け
- JavaScript のエスケープ:スクリプトのコンテキスト向け
- URL エンコード:URL パラメーター向け
- CSS のエスケープ:スタイルシートのコンテキスト向け
データがレンダリングされるコンテキストに応じて、常に出力をエンコードしてください。
その他の実装
以下については、references/python-sanitization.md を参照してください。
- Python の bleach ライブラリの使い方
- Flask/Django のテンプレートエスケープ
- サーバー側の検証パターン
以下については、references/nodejs-advanced.md を参照してください。
- すべてのメソッドを備えた XSSPrevention クラスの完全な実装
- Express ミドルウェア(xssProtection)
- React コンポーネント(SafeText、SafeHTML、SafeLink、useSanitizedInput)
- Helmet の CSP 設定
ベストプラクティス
✅ 推奨事項:
- デフォルトで出力をエンコードする
- 自動エスケープ機能のあるテンプレートエンジンを使用する
- CSP ヘッダーを実装する
- 許可リストを使ってリッチコンテンツをサニタイズする
- プロトコルの許可リストを使って URL を検証する
- HTTPOnly Cookie を使用する
- 定期的にセキュリティテストを実施する
- セキュリティに優れたフレームワークを活用する
❌ 禁止事項:
- ユーザー入力を信頼する
- 安全でない関数(eval、innerHTML)を使用する
- 利便性のためにセキュリティ機能を無効にする
- クライアント側の検証だけに頼る
- 許可リストではなく拒否リストを使用する
- コンテキストに応じたエンコードを省略する
- 任意のスクリプト実行を許可する
セキュリティチェックリスト
- すべての出力をコンテキスト(HTML、属性、JS)に応じてエンコードする
- 許可リスト(拒否リストではなく)を使って HTML をサニタイズする
- 厳格な CSP ヘッダーを実装する
- セッションには HTTPOnly Cookie を使用する
- URL を検証してサニタイズする
- ユーザーコンテンツに innerHTML を使用しない
- 定期的にセキュリティテストを実施する
リソース
コメント
Markdown 対応