[红日安全]代码审计Day12 - 误用htmlentities函数引发的漏洞
字数 1482 2025-08-18 11:37:37

HTML实体编码误用引发的安全漏洞分析

1. 漏洞背景

本文分析了由于PHP中htmlentities()函数使用不当导致的安全漏洞,主要包括XSS(跨站脚本攻击)和SQL注入两种类型。该漏洞源于开发者对htmlentities()函数参数配置不当,未能正确处理单引号和双引号的转义。

2. htmlentities函数详解

2.1 函数定义

string htmlentities ( string $string [, int $flags = ENT_COMPAT | ENT_HTML401 [, string $encoding = ini_get("default_charset") [, bool $double_encode = true ]]] )

2.2 参数说明

  • $string: 要转换的字符串
  • $flags: 指定如何处理引号,有三种可选值:
    • ENT_COMPAT(默认): 只转换双引号
    • ENT_QUOTES: 转换双引号和单引号
    • ENT_NOQUOTES: 不转换任何引号
  • $encoding: 字符编码,默认为PHP配置的默认字符集
  • $double_encode: 是否对已存在的HTML实体进行二次编码

2.3 安全影响

错误配置flags参数会导致:

  • 当使用ENT_COMPATENT_NOQUOTES时,单引号可能不会被转义
  • 在输出到HTML或拼接SQL语句时,可能导致XSS或SQL注入漏洞

3. 漏洞案例分析

3.1 案例1:XSS漏洞

漏洞代码片段

foreach($_GET as $key => $value){
    $value = intval($value); // 只处理value,未处理key
}
echo '<a href="'.$query.'">'.$query.'</a>';

漏洞点分析

  1. 只对$value进行类型转换,未处理$key
  2. 输出时虽然使用了htmlentities,但默认参数(ENT_COMPAT)不转义单引号
  3. 攻击者可构造恶意payload闭合单引号并注入JavaScript代码

攻击Payload

/?a'onclick%3dalert(1)%2f%2f=c

3.2 案例2:DM企业建站系统SQL注入

漏洞代码片段

// 登录处理代码
$user = $_POST['user'];
$query = "SELECT * FROM admin WHERE user='".$user."'";

// 过滤函数
function htmlentitiesdm($str){
    return htmlentities($str, ENT_NOQUOTES); // 不转义任何引号
}

漏洞点分析

  1. 使用htmlentities()但设置ENT_NOQUOTES参数,不转义单引号
  2. 用户输入直接拼接到SQL语句中,导致SQL注入
  3. 虽然考虑了XSS防护,但错误配置导致SQL注入风险

修复方式
将参数改为ENT_QUOTES,同时转义单引号和双引号:

function htmlentitiesdm($str){
    return htmlentities($str, ENT_QUOTES);
}

4. 漏洞验证方法

4.1 XSS验证

构造包含JavaScript事件的payload,观察是否执行:

http://example.com/?a'onclick='alert(1)//

4.2 SQL注入验证

使用时间盲注技术验证:

username=admin' AND (SELECT * FROM (SELECT(SLEEP(5)))a)-- 

观察响应时间是否延迟5秒

5. 安全防护建议

  1. 正确使用htmlentities函数

    • 始终使用ENT_QUOTES参数,确保单双引号都被转义
    • 示例:htmlentities($input, ENT_QUOTES)
  2. 防御SQL注入

    • 使用预处理语句(PDO或MySQLi)
    • 如果必须拼接SQL,确保正确转义所有引号
  3. 输入验证

    • 对用户输入进行严格的白名单验证
    • 根据上下文使用适当的过滤函数
  4. 输出编码

    • 根据输出上下文(HTML/JS/URL)使用适当的编码函数
    • htmlspecialchars(), urlencode()

6. CTF题目分析

题目代码

$username = @clean((string)$_GET['username']);
$password = @clean((string)$_GET['password']);
$query='SELECT * FROM ctf.users WHERE name=\''.$username.'\' AND pass=\''.$password.'\';';

过滤函数

function clean($str){
    if(get_magic_quotes_gpc()){
        $str=stripslashes($str);
    }
    return htmlentities($str, ENT_QUOTES);
}

解题思路

  1. 虽然使用了ENT_QUOTES转义引号,但可以通过HTML实体编码绕过
  2. 构造payload时使用HTML实体表示单引号:
    username=admin&password=or 1=1 %26%23x27;--
    
    其中%26%23x27;&#x27;的URL编码,在HTML中会被解码为单引号

7. 总结

  1. htmlentities()函数使用不当会导致严重的安全漏洞
  2. 必须使用ENT_QUOTES参数确保单双引号都被转义
  3. 安全开发应遵循"输入验证、输出编码"的原则
  4. 在防御XSS的同时,也要考虑其他类型漏洞的防护

8. 参考资源

  1. PHP官方文档 - htmlentities函数
  2. OWASP XSS防护指南
  3. SQL注入防护最佳实践
  4. HTML实体编码表
HTML实体编码误用引发的安全漏洞分析 1. 漏洞背景 本文分析了由于PHP中 htmlentities() 函数使用不当导致的安全漏洞,主要包括XSS(跨站脚本攻击)和SQL注入两种类型。该漏洞源于开发者对 htmlentities() 函数参数配置不当,未能正确处理单引号和双引号的转义。 2. htmlentities函数详解 2.1 函数定义 2.2 参数说明 $string : 要转换的字符串 $flags : 指定如何处理引号,有三种可选值: ENT_COMPAT (默认): 只转换双引号 ENT_QUOTES : 转换双引号和单引号 ENT_NOQUOTES : 不转换任何引号 $encoding : 字符编码,默认为PHP配置的默认字符集 $double_encode : 是否对已存在的HTML实体进行二次编码 2.3 安全影响 错误配置 flags 参数会导致: 当使用 ENT_COMPAT 或 ENT_NOQUOTES 时,单引号可能不会被转义 在输出到HTML或拼接SQL语句时,可能导致XSS或SQL注入漏洞 3. 漏洞案例分析 3.1 案例1:XSS漏洞 漏洞代码片段 : 漏洞点分析 : 只对 $value 进行类型转换,未处理 $key 输出时虽然使用了 htmlentities ,但默认参数( ENT_COMPAT )不转义单引号 攻击者可构造恶意payload闭合单引号并注入JavaScript代码 攻击Payload : 3.2 案例2:DM企业建站系统SQL注入 漏洞代码片段 : 漏洞点分析 : 使用 htmlentities() 但设置 ENT_NOQUOTES 参数,不转义单引号 用户输入直接拼接到SQL语句中,导致SQL注入 虽然考虑了XSS防护,但错误配置导致SQL注入风险 修复方式 : 将参数改为 ENT_QUOTES ,同时转义单引号和双引号: 4. 漏洞验证方法 4.1 XSS验证 构造包含JavaScript事件的payload,观察是否执行: 4.2 SQL注入验证 使用时间盲注技术验证: 观察响应时间是否延迟5秒 5. 安全防护建议 正确使用htmlentities函数 : 始终使用 ENT_QUOTES 参数,确保单双引号都被转义 示例: htmlentities($input, ENT_QUOTES) 防御SQL注入 : 使用预处理语句(PDO或MySQLi) 如果必须拼接SQL,确保正确转义所有引号 输入验证 : 对用户输入进行严格的白名单验证 根据上下文使用适当的过滤函数 输出编码 : 根据输出上下文(HTML/JS/URL)使用适当的编码函数 如 htmlspecialchars() , urlencode() 等 6. CTF题目分析 题目代码 : 过滤函数 : 解题思路 : 虽然使用了 ENT_QUOTES 转义引号,但可以通过HTML实体编码绕过 构造payload时使用HTML实体表示单引号: 其中 %26%23x27; 是 &#x27; 的URL编码,在HTML中会被解码为单引号 7. 总结 htmlentities() 函数使用不当会导致严重的安全漏洞 必须使用 ENT_QUOTES 参数确保单双引号都被转义 安全开发应遵循"输入验证、输出编码"的原则 在防御XSS的同时,也要考虑其他类型漏洞的防护 8. 参考资源 PHP官方文档 - htmlentities函数 OWASP XSS防护指南 SQL注入防护最佳实践 HTML实体编码表