你真的会过滤XSS吗?5分钟深刻理解htmlspecialchars函数

前言

一个很常见的现象 ,我们去搜索如何防御 XSS 攻击的时候,经常会看到一种防御方式就是使用htmlspecialchars,印象里之前在初学阶段,面试官在问及我如何防御 XSS 漏洞的时候,我也最喜欢说使用htmlspcialchars去过滤,那这种过滤方法真的安全吗?

今天在这篇文章里我们主要涉及到讨论 htmlspecialchars的过滤效果及不同效果是否存在漏洞及配套的绕过手法。

Htmlspecialchars 函数介绍

htmlspecialchars 函数是 PHP 中的一个内置函数,它用于将特定的 HTML 字符转换为 HTML 实体字符。在 HTML 中,某些字符如 <, >, ", ', 和 & 具有特殊含义,分别代表HTML的标签、结束标签、字符引用和实体引用。如果想要在 HTML 中输出这些字符而不让它们被浏览器解释为 HTML 标签或字符引用,就需要使用 htmlspecialchars 函数将它们转换为相应的 HTML 实体。
函数的基本语法如下:

htmlspecialchars(string $string, int $quote_style = ENT_COMPAT, string $encoding = 'UTF-8', bool $double_encode = true)

参数说明:

  • $string:需要转换的字符串。
  • $quote_style:指定引号的风格。通常有三个可选值:ENT_COMPATENT_QUOTESENT_NOQUOTESENT_COMPAT 会输出成 &lt;&gt;&quot;&apos;&amp;ENT_QUOTES 会在 ENT_COMPAT 的基础上将单引号也转换为实体字符(&#039;),ENT_NOQUOTES 则不会输出引号。
  • $encoding:设置字符编码,默认是 UTF-8
  • $double_encode:布尔值,指示是否对已经存在的实体进行再次编码。
    使用 htmlspecialchars 函数可以避免跨站脚本攻击(XSS),因为它可以确保用户输入的字符串被正确地处理,不会因为浏览器解释特殊字符而执行不必要的脚本。

函数过滤效果示例

首先我们编写一段最基本的代码,用于接收GET传送的参数comment,其后端处理代码如下:

<?php
if ($_SERVER["REQUEST_METHOD"] == "GET") {
    $comment =$_GET['comment'];

    echo "<h1>您的评论:</h1>";
    echo "<h2 align='center'>没有找到和" . htmlspecialchars($comment) . "相关的结果。</h2>";
}
?>

此时我们构造数据包,向comment参数发送最简单的 XSS 攻击语句,可以从数据包中看到,htmlspecialchars过滤了尖括号:

此时即使前端可以反应我们输入的数据,但是无法被当作 JS 代码执行:

请注意,这里我们使用的是默认的htmlspecialchars,如果alert(1)修改为alert("1"),那么其中的双引号也会被转义。

如何绕过,场景是什么

可以看到过滤是不成功的,那么网上的各种绕过是怎么回事呢?

经过笔者的研究,发现大部分的htmlspecialchars的绕过场景是这样的,后端代码如下:

<?php
if ($_SERVER["REQUEST_METHOD"] == "GET") {
    $comment =$_GET['comment'];
    // 对输入进行HTML实体编码
    echo "<h1>您的评论:</h1>";
    $comment=htmlspecialchars($comment);
    // 这里增加了一个表单输入,以便用户可以输入关键词进行搜索
    echo "<form action='' method='get'>";
    echo "<input type='text' name='keyword' value='$comment'>";
    echo "<input type='submit' value='搜索'>";
    echo "</form>";
}
?>

此时我们再度去传送相同的数据包,会发现如下的返回数据包,在这个数据包中我们传入的内容在经过htmlspecialchars函数处理后,被被赋予到<input> 块中的value ,在这个过程中,尖括号被转义导致无法正常执行想要执行的恶意javascript代码,但是此时我们使用的是默认的htmlspcialchars,在这种情况下,value 是使用单引号闭合的,那我们可以不可以通过单引号闭合去达到绕过的效果呢?

以上想法付诸实践,构造恶意 payload 如下:

http://xxx.COM/xss.php?comment=' onmouseover=javascript:alert(123) >

发送数据包后返回的数据包如下,可以看到闭合完成:

访问目标网页,触发 XSS 漏洞:

思考,如果 input标签里闭合方式是双引号还可以完成吗?此时我们修改后端代码如下:

<?php
if ($_SERVER["REQUEST_METHOD"] == "GET") {
    $comment =$_GET['comment'];
    $comment=htmlspecialchars($comment);
    // 对输入进行HTML实体编码
    echo "<h1>您的评论:</h1>";
    // 这里增加了一个表单输入,以便用户可以输入关键词进行搜索
    echo "<form action='' method='get'>";
    echo '<input type="text" name="keyword" value="$comment">';
    echo "<input type='submit' value='搜索'>";
    echo "</form>";
}
?>

可以看到返回的数据包中,双引号被转义,而前端也无法正常执行恶意的Javascript代码,因此达到防御的效果:

思考,如何防御第一种使用单引号闭合的效果?

此时我们关注到这样一个参数,

  • $quote_style:指定引号的风格。通常有三个可选值:ENT_COMPATENT_QUOTESENT_NOQUOTESENT_COMPAT 会输出成 &lt;&gt;&quot;&apos;&amp;ENT_QUOTES 会在 ENT_COMPAT 的基础上将单引号也转换为实体字符(&#039;),ENT_NOQUOTES 则不会输出引号。

也就是说,如果不设置这个参数,默认只过滤双引号而不过滤单引号,那么此时我们修改后端代码如下:

<?php
if ($_SERVER["REQUEST_METHOD"] == "GET") {
    $comment =$_GET['comment'];
    // 对输入进行HTML实体编码
    echo "<h1>您的评论:</h1>";
    $comment=htmlspecialchars($comment,int $quote_style = ENT_QUOTES);
    // 这里增加了一个表单输入,以便用户可以输入关键词进行搜索
    echo "<form action='' method='get'>";
    echo "<input type='text' name='keyword' value='$comment'>";
    echo "<input type='submit' value='搜索'>";
    echo "</form>";
}
?>

此时再此发送恶意的单引号过滤方法,那么返回的数据包如下,可以看到之前的绕过方法已经不奏效了,无法达到绕过。

因此其实对htmlspecialchars 的理解就很简单了,这个函数默认过滤尖括号,井号等危险符号,同时过滤双引号,想要绕过的话,需要在有单引号参数赋值的情况下通过构造闭合去绕过,如果这个函数设置了额外的参数,比如连单引号也转义,那么就无法绕过。

总结

在本篇文章里,我们主要学习了htmlspcialchars函数的过滤效果、默认的过滤和额外过滤效果的不同,以及特定情况下的绕过手法,XSS 博大精深,攻防之间需要从业人员更多的钻研和心血。

  • 57
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值