XSS防御完全指南 - XSS安全知识库

·
2026-01-16 08:16:13

一、XSS防御核心原则

XSS防御遵循"纵深防御"策略,包含多个层次:

防御三原则

1. 输入验证:永远不要信任用户输入

2. 输出编码:在输出到页面前进行适当编码

3. 纵深防御:使用多层防护机制

1.1 为什么需要多层防御?

单一防护措施可能被绕过

不同场景需要不同的防护策略

防止人为失误导致的安全漏洞

符合安全编码最佳实践

二、输入验证与过滤

2.1 白名单验证(推荐)

只接受符合预期格式的输入:

// PHP示例

function validateUsername($username) {

// 只允许字母、数字和下划线,长度3-20

if (!preg_match('/^[a-zA-Z0-9_]{3,20}$/', $username)) {

throw new Exception('无效的用户名格式');

}

return $username;

}

// 验证邮箱

function validateEmail($email) {

if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {

throw new Exception('无效的邮箱地址');

}

return $email;

}

// JavaScript客户端验证

function validateInput(input, type) {

const patterns = {

username: /^[a-zA-Z0-9_]{3,20}$/,

email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,

phone: /^1[3-9]\d{9}$/,

url: /^https?:\/\/.+/

};

return patterns[type]?.test(input) || false;

}

2.2 黑名单过滤(不推荐作为唯一防御)

// 移除危险字符(容易被绕过)

function removeXSS($input) {

$dangerous = ['', 'javascript:', 'onerror='];

return str_ireplace($dangerous, '', $input);

}

// 更好的方式是使用HTML Purifier等库

2.3 内容长度限制

// 限制输入长度

function limitLength(input, maxLength = 200) {

if (input.length > maxLength) {

throw new Error('输入超过最大长度限制');

}

return input;

}

三、输出编码策略

3.1 HTML上下文编码

在HTML标签之间输出时:

// PHP

function encodeHTML($str) {

return htmlspecialchars($str, ENT_QUOTES | ENT_HTML5, 'UTF-8');

}

// 使用示例

echo '

' . encodeHTML($userInput) . '
';

// JavaScript

function encodeHTML(str) {

const div = document.createElement('div');

div.textContent = str;

return div.innerHTML;

}

// 或使用现成方法

function escapeHTML(str) {

return str

.replace(/&/g, '&')

.replace(//g, '>')

.replace(/"/g, '"')

.replace(/'/g, ''')

.replace(/\//g, '/');

}

3.2 HTML属性上下文编码

function encodeHTMLAttribute($str) {

// 除了HTML编码,还要处理属性特殊字符

return htmlspecialchars($str, ENT_QUOTES | ENT_HTML5, 'UTF-8');

}

3.3 JavaScript上下文编码

// JavaScript中安全地插入动态内容

function safeInnerHTML(element, html) {

// 使用textContent代替innerHTML

element.textContent = html;

}

// 或使用DOMPurify库

import DOMPurify from 'dompurify';

element.innerHTML = DOMPurify.sanitize(html);

3.4 URL上下文编码

// PHP

$safeURL = 'https://example.com/search?q=' . urlencode($userInput);

// 验证URL协议

function validateURL($url) {

$parsed = parse_url($url);

if (!in_array($parsed['scheme'] ?? '', ['http', 'https'])) {

throw new Exception('不允许的URL协议');

}

return $url;

}

// JavaScript

const safeURL = 'https://example.com/search?q=' + encodeURIComponent(userInput);

// 验证URL

function isValidURL(url) {

try {

const parsed = new URL(url);

return ['http:', 'https:'].includes(parsed.protocol);

} catch {

return false;

}

}

3.5 CSS上下文编码

function validateColor($color) {

if (!preg_match('/^#[0-9A-Fa-f]{6}$/', $color)) {

return '#000000'; // 默认颜色

}

return $color;

}

?>

四、内容安全策略(CSP)

4.1 CSP基础配置

content="default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'">

// PHP设置CSP头

header("Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-" . $nonce . "'; style-src 'self' 'nonce-" . $nonce . "'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'");

4.2 使用Nonce的CSP

// 生成随机nonce

$nonce = base64_encode(random_bytes(16));

// 设置CSP头

header("Content-Security-Policy: script-src 'nonce-$nonce' 'strict-dynamic'");

?>

4.3 CSP报告

// 设置CSP报告端点

header("Content-Security-Policy: default-src 'self'; report-uri /csp-report; report-to csp-endpoint");

header("Report-To: {\"group\":\"csp-endpoint\",\"max_age\":10886400,\"endpoints\":[{\"url\":\"/csp-report\"}]}");

// 处理CSP报告

// /csp-report 端点

$report = json_decode(file_get_contents('php://input'), true);

if ($report) {

// 记录违规信息

error_log('CSP Violation: ' . json_encode($report));

// 可以发送到安全监控系统

sendToSecurityMonitor($report);

}

CSP最佳实践

1. 从严格策略开始,逐步放宽

2. 使用nonce或hash而非'unsafe-inline'

3. 启用报告功能监控违规

4. 定期审查和更新CSP策略

五、Cookie安全配置

5.1 HttpOnly和Secure标志

// PHP设置安全Cookie

setcookie(

'session_id',

$sessionId,

[

'expires' => time() + 3600,

'path' => '/',

'domain' => '.example.com',

'secure' => true, // 仅HTTPS

'httponly' => true, // 禁止JS访问

'samesite' => 'Strict' // 防CSRF

]

);

// Express.js示例

app.use(session({

secret: 'your-secret-key',

cookie: {

secure: true,

httpOnly: true,

sameSite: 'strict',

maxAge: 3600000

}

}));

5.2 SameSite Cookie

Strict:完全禁止跨站发送

Lax:允许部分跨站场景(GET请求)

None:允许跨站(需配合Secure)

六、框架级别的防御

6.1 使用模板引擎的自动转义

{{ userInput }} {# 自动HTML转义 #}

{{ userInput|raw }} {# 禁用转义(危险!) #}

// React自动转义

function UserProfile({ name }) {

return

{name}
; // 自动转义

}

// 危险的做法(不推荐)

function DangerousComponent({ html }) {

return

;

}

6.2 框架内置的XSS防护

// Angular自动转义

{{ userInput }}

// Vue.js自动转义

{{ userInput }}

6.3 使用安全的API

// 使用textContent代替innerHTML

element.textContent = userInput; // 安全

element.innerHTML = userInput; // 危险

// 使用setAttribute代替直接赋值

element.setAttribute('title', userInput); // 相对安全

element.title = userInput; // 也可以

// 避免eval和Function构造器

eval(userInput); // 极度危险

new Function(userInput)(); // 极度危险

// 使用JSON.parse代替eval

const data = JSON.parse(jsonString); // 安全

七、完整的XSS防御清单

开发阶段

☑ 对所有用户输入进行验证

☑ 在适当的上下文进行输出编码

☑ 使用自动转义的模板引擎

☑ 避免使用innerHTML、eval等危险API

☑ 实施严格的CSP策略

☑ 配置安全的Cookie属性

☑ 使用HTTPS传输敏感数据

测试阶段

☑ 进行XSS安全测试

☑ 使用自动化扫描工具

☑ 人工审查关键代码

☑ 测试CSP配置是否生效

☑ 验证所有输入输出点

部署阶段

☑ 启用WAF(Web应用防火墙)

☑ 配置安全响应头

☑ 定期更新框架和依赖库

☑ 监控安全日志

☑ 实施入侵检测系统

八、不同场景的防御策略

8.1 富文本编辑器

// 使用DOMPurify清理HTML

import DOMPurify from 'dompurify';

function sanitizeRichText(html) {

return DOMPurify.sanitize(html, {

ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'u', 'h1', 'h2', 'h3', 'ul', 'ol', 'li', 'a'],

ALLOWED_ATTR: ['href', 'title', 'target'],

ALLOW_DATA_ATTR: false

});

}

8.2 Markdown渲染

// 使用marked + DOMPurify

import marked from 'marked';

import DOMPurify from 'dompurify';

function renderMarkdown(markdown) {

const html = marked(markdown);

return DOMPurify.sanitize(html);

}

8.3 JSON API

// 设置正确的Content-Type

header('Content-Type: application/json');

// 输出JSON数据

echo json_encode($data, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);

九、总结

XSS防御是一个系统工程,需要在多个层面实施防护:

输入层:验证和过滤用户输入

处理层:安全地处理和存储数据

输出层:根据上下文进行适当编码

HTTP层:配置安全响应头和Cookie

客户端层:使用CSP等浏览器安全特性

记住:永远不要信任用户输入,永远进行适当的输出编码!

上一篇:Cookie窃取实战

返回知识库

下一篇:CSP配置实战指南