双手一摊与我无关 發表於 2026-5-3 17:24:46

PHP中HTML标签过滤的5种有效方法

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">什么是XSS攻击?</a></li><li><a href="#_label1">方法一:htmlspecialchars() - 最常用的转义方法</a></li><li><a href="#_label2">方法二:strip_tags() - 彻底移除HTML标签</a></li><li><a href="#_label3">方法三:filter_var() - 使用PHP过滤器扩展</a></li><li><a href="#_label4">方法四:HTMLPurifier - 企业级解决方案</a></li><li><a href="#_label5">方法五:自定义过滤函数</a></li><li><a href="#_label6">实战:根据不同场景选择防护策略</a></li><ul class="second_class_ul"><li><a href="#_lab2_6_0">场景1:用户评论(允许有限HTML)</a></li><li><a href="#_lab2_6_1">场景2:显示用户名(纯文本)</a></li><li><a href="#_lab2_6_2">场景3:URL参数</a></li></ul><li><a href="#_label7">完整的安全防护示例</a></li><ul class="second_class_ul"></ul><li><a href="#_label8">防御深度建议</a></li><ul class="second_class_ul"></ul><li><a href="#_label9">总结</a></li><ul class="second_class_ul"></ul></ul></div><p class="maodian"><a name="_label0"></a></p><h2>什么是XSS攻击?</h2>
<p>XSS(Cross-Site Scripting)攻击是指攻击者在网页中插入恶意脚本,当其他用户浏览该页面时,恶意脚本会被执行,从而盗取用户信息、会话令牌或进行其他恶意操作。</p>
<p class="maodian"><a name="_label1"></a></p><h2>方法一:htmlspecialchars() - 最常用的转义方法</h2>
<p><code>htmlspecialchars()</code> 是PHP中最基本的XSS防护函数,它将特殊字符转换为HTML实体:</p>
<div class="jb51code"><pre class="brush:php;">&lt;?php
$input = '&lt;script&gt;alert("XSS攻击")&lt;/script&gt;&lt;p&gt;正常内容&lt;/p&gt;';
$safe_output = htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
echo $safe_output;
// 输出:&amp;lt;script&amp;gt;alert(&amp;quot;XSS攻击&amp;quot;)&amp;lt;/script&amp;gt;&amp;lt;p&amp;gt;正常内容&amp;lt;/p&amp;gt;
</pre></div>
<p><strong>参数详解:</strong></p>
<ul><li><code>ENT_QUOTES</code>:转换双引号和单引号</li><li><code>UTF-8</code>:指定字符编码,防止编码绕过攻击</li></ul>
<p><strong>适用场景:</strong> 纯文本输出,不需要保留任何HTML格式</p>
<p class="maodian"><a name="_label2"></a></p><h2>方法二:strip_tags() - 彻底移除HTML标签</h2>
<p>如果你确定不需要任何HTML标签,使用<code>strip_tags()</code>可以彻底移除它们:</p>
<div class="jb51code"><pre class="brush:php;">&lt;?php
$input = '&lt;script&gt;alert("XSS")&lt;/script&gt;&lt;p&gt;正文内容&lt;/p&gt;&lt;b&gt;加粗文本&lt;/b&gt;';
$safe_output = strip_tags($input);
echo $safe_output;
// 输出:alert("XSS")正文内容加粗文本
</pre></div>
<p><strong>选择性保留标签:</strong></p>
<div class="jb51code"><pre class="brush:php;">&lt;?php
$input = '&lt;script&gt;alert("XSS")&lt;/script&gt;&lt;p&gt;正文&lt;/p&gt;&lt;b&gt;加粗&lt;/b&gt;&lt;i&gt;斜体&lt;/i&gt;';
$safe_output = strip_tags($input, '&lt;p&gt;&lt;b&gt;'); // 只保留&lt;p&gt;和&lt;b&gt;标签
echo $safe_output;
// 输出:&lt;p&gt;正文&lt;/p&gt;&lt;b&gt;加粗&lt;/b&gt;斜体
</pre></div>
<ul><li><strong>优点:</strong> 简单直接,性能好</li><li><strong>缺点:</strong> 无法过滤标签内的属性</li></ul>
<p class="maodian"><a name="_label3"></a></p><h2>方法三:filter_var() - 使用PHP过滤器扩展</h2>
<p>PHP过滤器扩展提供了更规范的过滤方式:</p>
<div class="jb51code"><pre class="brush:php;">&lt;?php
$input = '&lt;script&gt;alert("XSS")&lt;/script&gt;&lt;p&gt;正常内容&lt;/p&gt;';
$safe_output = filter_var($input, FILTER_SANITIZE_STRING);
echo $safe_output;
// 输出:alert("XSS")正常内容

// 专门用于过滤HTML
$html_output = filter_var($input, FILTER_SANITIZE_FULL_SPECIAL_CHARS);
</pre></div>
<p class="maodian"><a name="_label4"></a></p><h2>方法四:HTMLPurifier - 企业级解决方案</h2>
<p>对于需要保留安全HTML内容的场景,HTMLPurifier是最佳选择:</p>
<p><strong>安装方法:</strong></p>
<div class="jb51code"><pre class="brush:php;">composer require ezyang/htmlpurifier
</pre></div>
<p><strong>使用示例:</strong></p>
<div class="jb51code"><pre class="brush:php;">&lt;?php
require_once 'vendor/autoload.php';

$config = HTMLPurifier_Config::createDefault();
// 自定义配置
$config-&gt;set('HTML.Allowed', 'p,br,strong,em,ul,ol,li,a');
$config-&gt;set('AutoFormat.RemoveEmpty', true);

$purifier = new HTMLPurifier($config);

$input = '&lt;script&gt;alert("XSS")&lt;/script&gt;&lt;p class="test"&gt;安全内容&lt;/p&gt;&lt;a href="http://example.com" rel="external nofollow"rel="external nofollow" &gt;链接&lt;/a&gt;';
$safe_output = $purifier-&gt;purify($input);
echo $safe_output;
// 输出:&lt;p&gt;安全内容&lt;/p&gt;&lt;a href="http://example.com" rel="external nofollow"rel="external nofollow" &gt;链接&lt;/a&gt;
</pre></div>
<p><strong>优势:</strong></p>
<ul><li>遵循HTML标准</li><li>支持细粒度配置</li><li>能过滤危险的标签属性</li><li>社区活跃,持续更新</li></ul>
<p class="maodian"><a name="_label5"></a></p><h2>方法五:自定义过滤函数</h2>
<p>针对特定需求,可以创建自定义过滤函数:</p>
<div class="jb51code"><pre class="brush:php;">&lt;?php
function advanced_xss_clean($data) {
    if (empty($data)) return '';
   
    // 递归处理数组
    if (is_array($data)) {
      return array_map('advanced_xss_clean', $data);
    }
   
    // 移除NULL字节
    $data = str_replace(chr(0), '', $data);
   
    // 转换特殊字符
    $data = htmlspecialchars($data, ENT_QUOTES | ENT_HTML5, 'UTF-8', true);
   
    // 移除危险的JavaScript模式
    $patterns = [
      '/javascript:/i',
      '/vbscript:/i',
      '/on\w+\s*=/i',    // 移除onclick等事件属性
      '/expression\s*\(/i' // 移除CSS表达式
    ];
   
    foreach ($patterns as $pattern) {
      $data = preg_replace($pattern, '', $data);
    }
   
    return $data;
}

// 使用示例
$input = '&lt;img src="javascript:alert(1)" onclick="malicious()"&gt;';
echo advanced_xss_clean($input);
?&gt;
</pre></div>
<p class="maodian"><a name="_label6"></a></p><h2>实战:根据不同场景选择防护策略</h2>
<p class="maodian"><a name="_lab2_6_0"></a></p><h3>场景1:用户评论(允许有限HTML)</h3>
<div class="jb51code"><pre class="brush:php;">&lt;?php
function filter_comment($content) {
    $allowed_tags = '&lt;p&gt;&lt;br&gt;&lt;strong&gt;&lt;em&gt;&lt;ul&gt;&lt;ol&gt;&lt;li&gt;&lt;a&gt;';
    $content = strip_tags($content, $allowed_tags);
   
    // 进一步使用HTMLPurifier进行严格过滤
    require_once 'HTMLPurifier.auto.php';
    $purifier = new HTMLPurifier();
    return $purifier-&gt;purify($content);
}
?&gt;
</pre></div>
<p class="maodian"><a name="_lab2_6_1"></a></p><h3>场景2:显示用户名(纯文本)</h3>
<div class="jb51code"><pre class="brush:php;">&lt;?php
function filter_username($username) {
    return htmlspecialchars(trim($username), ENT_QUOTES, 'UTF-8');
}
?&gt;
</pre></div>
<p class="maodian"><a name="_lab2_6_2"></a></p><h3>场景3:URL参数</h3>
<div class="jb51code"><pre class="brush:php;">&lt;?php
function filter_url($url) {
    $url = filter_var($url, FILTER_SANITIZE_URL);
    if (filter_var($url, FILTER_VALIDATE_URL)) {
      return htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
    }
    return '';
}
?&gt;
</pre></div>
<p class="maodian"><a name="_label7"></a></p><h2>完整的安全防护示例</h2>
<div class="jb51code"><pre class="brush:php;">&lt;?php
class SecurityHelper {
   
    public static function xss_clean($data, $context = 'text') {
      if (empty($data)) return $data;
      
      if (is_array($data)) {
            return array_map(, $data);
      }
      
      switch ($context) {
            case 'html':
                // 使用HTMLPurifier处理富文本
                return self::purify_html($data);
               
            case 'attribute':
                // 用于HTML属性
                return self::escape_attribute($data);
               
            case 'text':
            default:
                // 纯文本转义
                return htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
      }
    }
   
    private static function purify_html($html) {
      require_once 'HTMLPurifier.auto.php';
      $config = HTMLPurifier_Config::createDefault();
      $config-&gt;set('HTML.Allowed', 'p,br,strong,em,ul,ol,li,a');
      $purifier = new HTMLPurifier($config);
      return $purifier-&gt;purify($html);
    }
   
    private static function escape_attribute($data) {
      return htmlspecialchars($data, ENT_QUOTES, 'UTF-8', false);
    }
}

// 使用示例
$user_input = [
    'username' =&gt; '&lt;script&gt;alert("xss")&lt;/script&gt;',
    'comment' =&gt; '&lt;p&gt;正常评论&lt;/p&gt;&lt;script&gt;恶意代码&lt;/script&gt;',
    'website' =&gt; 'javascript:alert(1)'
];

$cleaned_data = SecurityHelper::xss_clean($user_input);
print_r($cleaned_data);
?&gt;
</pre></div>
<p class="maodian"><a name="_label8"></a></p><h2>防御深度建议</h2>
<ul><li><strong>输入验证</strong>:在接收数据时进行严格验证</li><li><strong>输出转义</strong>:根据输出上下文进行适当的转义</li><li><strong>内容安全策略(CSP)</strong>:设置HTTP头</li></ul>
<div class="jb51code"><pre class="brush:php;">header("Content-Security-Policy: default-src 'self'");</pre></div>
<ul><li><strong>HttpOnly Cookie</strong>:防止Cookie被JavaScript读取</li><li><strong>框架安全特性</strong>:优先使用框架提供的安全方法</li></ul>
<p class="maodian"><a name="_label9"></a></p><h2>总结</h2>
<p>XSS防护是一个多层次的过程,需要根据具体场景选择合适的过滤策略:</p>
<ul><li><strong>纯文本输出</strong>:使用&nbsp;<code>htmlspecialchars()</code></li><li><strong>完全移除HTML</strong>:使用&nbsp;<code>strip_tags()</code></li><li><strong>保留安全HTML</strong>:使用 HTMLPurifier</li><li><strong>企业级应用</strong>:结合多种方法,建立完整防护体系</li></ul>
<p>记住:<strong>永远不要信任用户输入</strong>,在显示任何用户提供的数据之前,都要进行适当的过滤和转义。</p>
頁: [1]
查看完整版本: PHP中HTML标签过滤的5种有效方法