关于安全性:在PHP站点中避免xss攻击的最佳实践是什么

关于安全性:在PHP站点中避免xss攻击的最佳实践是什么

What are the best practices for avoiding xss attacks in a PHP site

我已配置PHP,以便打开魔术引号,并关闭全局寄存器。

我尽我所能一直为从用户输入派生的任何输出调用htmlentities()。

我有时也会在数据库中查找xss附带的常见信息,例如...

1
<script

我还应该做些什么,以及如何确保自己一直想做的事情始终完成。


对于成功防止XSS而言,转义输入并不是最好的选择。输出也必须转义。如果使用Smarty模板引擎,则可以使用|escape:'htmlall'修饰符将所有敏感字符转换为HTML实体(我使用自己的|e修饰符,这是上面的别名)。

我输入/输出安全性的方法是:

  • 存储未修改的用户输入(输入不转义HTML,仅通过PDO准备好的语句完成DB感知转义)
  • 在输出中进行转义,具体取决于您使用的输出格式(例如HTML和JSON需要不同的转义规则)

我认为,在输入过程中,仅在输出时,不应逃避任何操作。由于(大多数时候)您不能假设您知道数据的去向。例如,如果您有一个表单,该表单使用了以后要在发送的电子邮件中显示的数据,则需要进行不同的转义(否则,恶意用户可能会重写您的电子邮件标题)。

换句话说,您只能在数据"离开"您的应用程序的最后一刻转义:

  • 项目清单
  • 写入XML文件,转义为XML
  • 写入数据库,转义(针对特定的DBMS)
  • 写电子邮件,转义电子邮件
  • 等等

简而言之:

  • 您不知道数据往哪里去
  • 数据实际上可能会在一个以上的地方结束,需要使用不同的转义机制,但不能同时
  • 为错误的目标转义的数据确实不好。 (例如,收到一封主题为"转到汤米的酒吧"的电子邮件。)
  • 如果您在输入层对数据进行转义(或者需要再次对它进行转义,等等),则会出现Esp#3。

    PS:我将不使用magic_quotes的建议放在第二位,这些都是纯邪!


    有很多方法可以执行XSS(请参阅http://ha.ckers.org/xss.html),而且很难掌握。

    我个人将此委托给我正在使用的当前框架(例如Code Igniter)。虽然不完美,但它可能比我手工制作的例程捕捉到的更多。


    这是一个很好的问题。

    首先,除了确保输入内容安全(例如放入数据库中)外,不要转义输入中的文本。这样做的原因是您想保留输入的内容,以便可以不同的方式和位置在上下文中呈现它。在此处进行更改可能会损害您以后的演示文稿。

    当您显示数据时,应过滤掉不应该存在的内容。例如,如果没有理由在其中搜索javascript,然后将其删除。一种简单的方法是使用strip_tags函数,仅显示您允许的html标签。

    接下来,使用您拥有的内容并传递htmlentities或htmlspecialchars的思想,以将其中的内容更改为ASCII字符。根据上下文和您想要获得的结果执行此操作。

    我也建议关闭魔术引号。它已从PHP 6中删除,使用它被认为是不好的做法。有关详细信息,请访问http://us3.php.net/magic_quotes

    有关更多详细信息,请访问http://ha.ckers.org/xss.html

    这不是一个完整的答案,但有希望足以帮助您入门。


    rikh Writes:

    I do my best to always call htmlentities() for anything I am outputing that is derived from user input.

    有关此方面的帮助,请参见Joel的使代码看起来错误的文章。


    模板库。至少,这就是模板库应该做的。
    为了防止XSS,应该对所有输出进行编码。这不是主要应用程序/控制逻辑的任务,它应该仅由输出方法处理。

    如果您在代码中撒满htmlentities(),则总体设计是错误的。如您所建议,您可能会错过一两个景点。
    这就是为什么唯一的解决方案是严格的html编码->当输出vars被写入html / xml流时。

    不幸的是,大多数php模板库仅添加了自己的模板语法,而与输出编码,本地化,html验证或其他重要内容无关。也许其他人知道适合php的模板库?


    我依靠PHPTAL。

    与Smarty和纯PHP不同,它默认情况下会转义所有输出。这是安全方面的一大胜利,因为如果您忘记了某个地方的htmlspecialchars()|escape,则您的网站将不会受到威胁。

    XSS是HTML特定的攻击,因此HTML输出是防止它的正确位置。您不应该尝试对数据库中的数据进行预过滤,因为您可能需要将数据输出到另一种不接受HTML但有其自身风险的介质。


    如果您担心XSS攻击,则将输出字符串编码为HTML是解决方案。如果您记得将每个输出字符编码为HTML格式,则无法执行成功的XSS攻击。

    阅读更多:
    清理用户数据:如何以及在何处进行


    "魔术引号"是对一些最严重的XSS缺陷的治标之道,这些缺陷是通过转义输入中的所有内容而起作用的,这在设计上是错误的。唯一要使用它的情况是,您必须绝对使用已知的XSS粗心编写的现有PHP应用程序时。 (在这种情况下,即使使用"魔术引号",您也会遇到严重麻烦。)在开发自己的应用程序时,应禁用"魔术引号",而应遵循XSS安全做法。

    XSS是跨站点脚本漏洞,当应用程序在其[X] HTML,CSS,ECMAscript或其他浏览器解析的输出中包含来自外部源(用户输入,从其他网站等获取的字符串)的字符串时,没有进行适当的转义,跳转,就会发生这样,就不会出现小于号([X] HTML),单引号或双引号(ECMAscript)之类的特殊字符。正确的解决方案是始终根据输出语言的规则对字符串进行转义:使用[X] HTML中的实体,ECMAscript中的反斜杠等。

    因为很难跟踪不信任的内容和必须转义的内容,所以最好始终转义"文本字符串"而不是诸如HTML之类的"带有标记的文本"的所有内容。某些编程环境通过引入几种不兼容的字符串类型使之更容易:"字符串"(普通文本)," HTML字符串"(HTML标记)等等。那样,就不可能直接从"字符串"到" HTML字符串"进行隐式转换,而字符串成为HTML标记的唯一方法是将其传递给转义函数。

    尽管禁用它绝对是一个好主意,但"注册全局变量"处理的问题与XSS完全不同。


    对于大多数站点,转义所有用户输入就足够了。另外,请确保会话ID不会以URL结尾,以免它们从Referer链接到另一个站点的被盗。另外,如果允许用户提交链接,请确保不允许任何javascript:协议链接;一旦用户单击链接,它们将执行脚本。


    所有这些答案都是不错的选择,但是从根本上讲,XSS的解决方案是停止通过字符串操作生成HTML文档。

    对于任何应用程序,过滤输入始终是一个好主意。

    只要使用正确,使用htmlentities()和朋友转义输出就应该可以正常工作,但这在HTML上等同于通过使用mysql_real_escape_string($ var)连接字符串来创建SQL查询-它应该可以工作,但是可以验证您的工作的工作很少,可以说,与使用参数化查询之类的方法相比。

    长期的解决方案应该是应用程序内部构建页面,也许使用诸如DOM之类的标准接口,然后使用一个库(如libxml)来处理到XHTML / HTML / etc的序列化。当然,与流行和足够快还有很长的路要走,但是与此同时,我们必须通过字符串操作来构建HTML文档,这从本质上讲更具风险。


    我发现使用此功能有助于消除很多可能的xss攻击:
    http://www.codebelay.com/killxss.phps


    就个人而言,我将禁用magic_quotes。在PHP5 +中,默认情况下将其禁用,并且最好将其编码为好像根本不存在,因为它不能逃避一切,并且会从PHP6中删除。

    接下来,根据您要过滤的用户数据类型,您将决定下一步要执行的操作,例如如果只是文字,例如名称,然后strip_tags(trim(stripslashes()));或使用正则表达式检查范围。

    如果期望某个值范围,则创建一个有效值数组,并仅允许这些值通过(in_array($userData, array(...)))。

    如果要检查数字,请使用is_numeric强制执行整数或将其强制转换为特定类型,这应该可以防止人们尝试代替发送字符串。

    如果您使用的是PHP5.2 +,则考虑查看filter()并利用该扩展名可以过滤各种数据类型,包括电子邮件地址。文档不是特别好,但是正在改进。

    如果必须处理HTML,则应考虑使用类似PHP Input Filter或HTML Purifier的工具。 HTML Purifier还将验证HTML的一致性。我不确定输入过滤器是否仍在开发中。两者都将允许您定义一组可以使用的标签以及允许使用哪些属性。

    无论您做出什么决定,都请记住,永远不要相信任何来自用户(包括您自己!)的PHP脚本。


    当前,防止PHP应用程序中XSS的最佳方法是HTML Purifier(http://htmlpurifier.org/)。它的一个小缺点是它是一个相当大的库,最好与APC这样的操作码缓存一起使用。您可以在任何不受信任的内容输出到屏幕的地方使用它。 htmlentities,htmlspecialchars,filter_input,filter_var,strip_tags等要彻底得多。


    使您使用HttpOnly的任何会话cookie(或所有cookie)成为可能。在这种情况下,大多数浏览器都会从JavaScript隐藏cookie值。用户仍然可以手动复制cookie,但这有助于防止直接脚本访问。 StackOverflow在测试期间出现了此问题。

    这不是解决方案,只是墙上的另一块砖


    • 不信任用户输入
    • 转义所有自由文本输出
    • 不要使用magic_quotes;查看是否有特定于DBMS的变体,或使用PDO
    • 考虑尽可能使用仅HTTP的cookie,以避免任何恶意脚本能够劫持会话

    您至少应验证进入数据库的所有数据。并尝试验证离开数据库的所有数据。

    mysql_real_escape_string可以很好地防止SQL注入,但是XSS比较棘手。
    您应该尽可能地使用preg_match,stip_tags或htmlentities!


    使用现有的用户输入清理库来清除所有用户输入。除非您付出很多努力,否则您自己也无法实现。


    我发现最好的方法是使用允许您绑定代码的类,因此您不必担心手动转义数据。


    在不会引起错误警报的站点上,很难实现全面的sql injection / xss注入预防。在CMS中,最终用户可能希望使用链接到另一个站点的项目。

    我建议让所有用户使用NoScript安装FireFox ;-)


    推荐阅读