安全的XSS清洁功能(定期更新)

zua*_*auz 14 php security xss filtering sanitization

我现在一直在网上打猎几天试图解决这个问题,但得到了相互矛盾的答案.

是否有PHP的库,类或函数可以安全地清理/编码针对XSS的字符串?它需要定期更新以应对新的攻击.

我有几个用例:

用例1)我有一个纯文本字段,比如名字或姓氏

  • 用户将文本输入字段并提交表单
  • 在将其保存到数据库之前,我想a)修剪字符串前端和末尾的任何空格,以及b)从输入中删除所有HTML标记.它是一个名称文本字段,它们不应包含任何HTML.
  • 然后我将使用PDO预处理语句将其保存到数据库中.

我想我可以做trim(),strip_tags()然后使用Sanitize过滤器或带有白名单字符的RegEx.他们真的需要像这样的人物!和?或者< >以他们的名义,不是真的.

用例2)当从先前保存的数据库记录(或从先前提交的表单)输出内容到View/HTML时,我想彻底清除它以用于XSS.注意:它可能已经或可能没有经过用例1中的过滤步骤,因为它可能是不同类型的输入,因此假设没有进行消毒.

最初我虽然HTMLPurifier会做这个工作,但是当我向他们的支持提出问题时,它似乎不是我需要的:

这是试金石:如果用户提交<b>foo</b>它应该显示为<b>foo</b>foo?如果是前者,则不需要HTML Purifier.

所以我宁愿它出现,<b>foo</b>因为我不希望为简单的文本字段或任何执行的JavaScript显示任何HTML.

所以我一直在寻找能够为我做这一切的功能.我偶然发现了Kohana 3.0使用xss_clean方法,我猜它是有效的,但只有当你想保留HTML时才会这样.它现在已经从Kohana 3.1中弃用,因为它们已经用HTMLPurifier取代了它.所以我猜你应该做的HTML::chars()只是做这个代码:

public static function chars($value, $double_encode = TRUE)
{
    return htmlspecialchars( (string) $value, ENT_QUOTES, Kohana::$charset, $double_encode);
}
Run Code Online (Sandbox Code Playgroud)

现在显然你应该使用htmlentities而不是像Stack Overflow中的很多地方所提到的那样,因为它比htmlspecialchars更安全.

  • 那么如何正确使用htmlentities?
  • 这就是我需要的吗?
  • 它如何防止从此处列出的攻击发送的十六进制,十进制和base64编码值?

现在我看到htmlentities方法的第3个参数是转换中使用的字符集.现在我的站点/ db是UTF-8,但是表单提交的数据可能不是UTF-8编码,也许他们提交了ASCII或HEX,所以我可能需要先将其转换为UTF-8?这意味着一些代码如:

$encoding = mb_detect_encoding($input);
$input = mb_convert_encoding($input, 'UTF-8', $encoding);
$input = htmlentities($input, ENT_QUOTES, 'UTF-8');
Run Code Online (Sandbox Code Playgroud)

是还是不是?然后我仍然不确定如何防止十六进制,十进制和base64可能的XSS输入......

如果有一些库或开源PHP框架可以正确地进行XSS保护,我有兴趣看看它们是如何在代码中完成的.

任何帮助非常感谢,抱歉长篇文章!

phi*_*hag 24

回答这个大胆的问题:是的,有.它被称为htmlspecialchars.

它需要定期更新以应对新的攻击.

防止XSS攻击的正确方法不是抵制特定攻击,过滤/清理数据,而是在任何地方正确编码.

htmlspecialchars(或htmlentities)结合字符编码的合理决定(即UTF-8)和字符编码的明确规范足以防止所有XSS攻击.幸运的是,htmlspecialchars没有显式编码的调用(它假设ISO-8859-1)也适用于UTF-8.如果要显式,请创建辅助函数:

// Don't forget to specify UTF-8 as the document's encoding
function htmlEncode($s) {
    return htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
}
Run Code Online (Sandbox Code Playgroud)

哦,并解决形式问题:不要试图检测编码,它一定会失败.相反,请以UTF-8形式提供表格.每个浏览器都会以UTF-8发送用户输入.

解决具体问题:

(...)你应该使用htmlentities因为htmlspecialchars容易受到UTF-7 XSS攻击.

只有当浏览器认为文档是以UTF-7编码时,才能应用UTF-7 XSS漏洞.将文档编码指定为UTF-8(在HTTP标头/后面的元标记中<head>)可以防止这种情况.

此外,如果我没有检测到编码,是什么阻止攻击者下载html文件,然后将其更改为UTF-7或其他编码,然后从更改的html页面将POST请求提交回我的服务器?

此攻击情形不必要地复杂.攻击者可以制作一个UTF-7字符串,无需下载任何内容.

如果您接受攻击者的POST(即您接受匿名公共用户输入),您的服务器将只将UTF-7字符串解释为奇怪的UTF-8字符串.这不是问题,攻击者的帖子只会出现乱码.攻击者可以通过提交"grfnlk"一百次来达到同样的效果(发送奇怪的文本).

如果我的方法仅适用于UTF-8,则XSS攻击将通过,不是吗?

不,它不会.编码不是魔术.编码只是解释二进制字符串的一种方法.例如,字符串"ö" 2B 41 50 59以UTF-7(和C3 B6UTF-8)编码为(十六进制).解码2B 41 50 59为UTF-8会产生"+ APY" - 无害,看似随机的字符.

另外,htmlentities如何防止HEX或其他XSS攻击?

十六进制数据将被输出.发送"3C"的攻击者将发布消息"3C"."3C" 只有<在您主动尝试解释十六进制输入时才会变为,例如,主动将它们映射到unicode代码点然后输出它们.这只是意味着如果您接受的是纯UTF-8(例如base32编码的UTF-8)中的数据,您首先必须解压缩编码,然后htmlspecialchars在将其包含在HTML代码之前使用.

  • @zoszsoz通过对评论中每个点的反驳更新了答案.不要假设魔法;) (2认同)