在PHP站点中避免xss攻击的最佳实践是什么?

时间:2008-09-16 11:20:03

标签: php security xss

我配置了PHP,以便启用魔术引号并关闭注册全局。

我会尽力为我输出的任何来自用户输入的内容调用htmlentities()。

我偶尔也会搜索我的数据库,以获取xss附带的常用内容,例如...

<script

我还应该做些什么,以及如何确保我要做的事情始终完成。

20 个答案:

答案 0 :(得分:58)

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

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

  • 存储未修改的用户输入(输入时没有HTML转义,只能通过PDO预处理语句进行数据库感知转义)
  • 输出转义,具体取决于您使用的输出格式(例如HTML和JSON需要不同的转义规则)

答案 1 :(得分:18)

我认为在输入过程中不应该逃避任何事情,只能在输出上。因为(大部分时间)你不能假设你知道数据的去向。例如,如果您的表单中包含稍后显示在您发送的电子邮件中的数据,则需要进行不同的转义(否则恶意用户可能会重写您的电子邮件标题)。

换句话说,您只能在数据“离开”您的应用程序的最后时刻逃脱:

  • 列表项
  • 写入XML文件,转义为XML
  • 写入DB,转义(针对特定的DBMS)
  • 撰写电子邮件,转发电子邮件

简而言之:

  1. 您不知道数据的去向
  2. 数据实际上可能会在多个地方结束,需要不同的转义机制但不能同时
  3. 针对错误目标的数据转义真的不太好。 (例如,收到一封主题为“去汤米的酒吧”的电子邮件。)
  4. 如果您在输入图层转义数据(或者您需要再次对其进行转义等),则会出现Esp#3。

    PS:我会提出不使用magic_quotes的建议,那些是纯粹的邪恶!

答案 2 :(得分:12)

有许多方法可以做XSS(参见http://ha.ckers.org/xss.html)并且很难捕捉到。

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

答案 3 :(得分:10)

这是一个很好的问题。

首先,除了使其安全存储(例如放入数据库)之外,不要在输入上转义文本。这样做的原因是您希望保留输入的内容,以便您可以以不同的方式和位置进行上下文显示。在此处进行更改可能会影响您之后的演示。

当你去展示你的数据过滤掉不应该存在的东西时。例如,如果javascript没有理由在那里搜索并删除它。一种简单的方法是使用strip_tags函数并仅显示您允许的html标记。

接下来,拿走你所拥有的并通过它认为htmlentities或htmlspecialchars来改变那里的ascii字符。根据上下文和你想要的内容来做这件事。

我也建议关闭Magic Quotes。它已从PHP 6中删除,被认为是使用它的不良做法。详情请见http://us3.php.net/magic_quotes

有关详细信息,请查看http://ha.ckers.org/xss.html

这不是一个完整的答案,但希望足以帮助你开始。

答案 4 :(得分:7)

  

rikh写道:

     
    

我会尽力为我输出的任何来自用户输入的内容调用htmlentities()。

  

请参阅Joel在Making Code Look Wrong上的论文以获取有关此

的帮助

答案 5 :(得分:4)

模板库。或者至少,这就是模板库应该做的事情。 要防止XSS 所有输出都应编码。这不是主应用程序/控制逻辑的任务,它应该只由输出方法处理。

如果你在代码中撒上htmlentities(),整体设计是错误的。正如你的建议,你可能会错过一两个地方。 这就是为什么唯一的解决方案是严格的html编码 - &gt;当输出变量被写入html / xml流时。

不幸的是,大多数php模板库只添加自己的模板语法,但不关心输出编码,本地化,html验证或任何重要的事情。也许别人知道一个适合php的模板库?

答案 6 :(得分:4)

我依靠PHPTAL

与Smarty和普通PHP不同,默认情况下它会转义所有输出。这对安全性来说是一个巨大的胜利,因为如果您忘记某处htmlspecialchars()|escape,您的网站就不会变得难以理解。

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

答案 7 :(得分:2)

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

对任何应用程序来说,过滤输入总是一个好主意。

使用htmlentities()转义输出,并且朋友应该正常工作,但是这相当于通过将字符串与mysql_real_escape_string($ var)连接来创建SQL查询 - 它应该可以工作,但是可以减少与使用参数化查询等方法相比,可以确认您的工作。

长期解决方案应该是应用程序在内部构建页面,可能使用像DOM这样的标准接口,然后使用库(如libxml)来处理到XHTML / HTML /等的序列化。当然,我们距离流行和足够快的人还有很长的路要走,但与此同时我们必须通过字符串操作来构建我们的HTML文档,这本身就更具风险。

答案 8 :(得分:2)

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

答案 9 :(得分:2)

对于大多数网站来说,转义所有用户输入就足够了。还要确保会话ID不会在URL中结束,因此不能从Referer链接中窃取到其他站点。此外,如果您允许用户提交链接,请确保不允许javascript:协议链接;一旦用户点击链接,这些就会执行一个脚本。

答案 10 :(得分:2)

就个人而言,我会禁用magic_quotes。在PHP5 +中,默认情况下它被禁用,最好是编码,好像它根本不存在,因为它不会逃避所有内容,它将从PHP6中删除。

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

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

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

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

如果您必须处理HTML,那么您应该考虑PHP Input FilterHTML Purifier之类的内容。 HTML Purifier还将验证HTML的一致性。我不确定输入过滤器是否仍在开发中。两者都允许您定义一组可以使用的标记以及允许的属性。

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

答案 11 :(得分:2)

对于一些最糟糕的XSS漏洞而言,“魔术引用”是一种姑息性的补救措施,它通过逃避输入中的所有内容来实现,这在设计上是错误的。人们想要使用它的唯一情况是当你绝对必须使用已知的关于XSS的不经意写的PHP应用程序时。 (在这种情况下,即使使用“魔术引号”,您也会遇到严重问题。)在开发自己的应用程序时,您应该禁用“魔术引号”并改为遵循XSS安全做法。

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

因为很难跟踪不受信任且必须被转义的内容,所以总是要逃避所有“文本字符串”而不是像HTML这样的语言中的“带标记的文本”。一些编程环境通过引入几个不兼容的字符串类型使其变得更容易:“string”(普通文本),“HTML字符串”(HTML标记)等。这样,从“字符串”到“HTML字符串”的直接隐式转换是不可能的,字符串可以成为HTML标记的唯一方法是将其传递给转义函数。

“注册全局”虽然禁用它绝对是一个好主意,但它处理的问题与XSS完全不同。

答案 12 :(得分:2)

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

了解更多: Sanitizing user data: How and where to do it

答案 13 :(得分:1)

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

答案 14 :(得分:1)

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

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

答案 15 :(得分:1)

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

mysql_real_escape_string可以防止SQL注入,但XSS比较棘手。 你应该尽可能preg_match,stip_tags或htmlentities!

答案 16 :(得分:1)

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

答案 17 :(得分:0)

使用现有的用户输入清理库清除所有用户输入。除非你把很多的努力投入其中,否则自己实施它将永远不会有效。

答案 18 :(得分:0)

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

答案 19 :(得分:-1)

在不会导致错误警报的站点上实施彻底的SQL注入/ xss注入防护很困难。在CMS中,最终用户可能希望使用链接到其他网站上的项目的<script><object>

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

相关问题