如何防止跨站脚本攻击?

5

我正在使用php,mysql和smarty进行开发,并且有用户可以进行评论等操作的地方。在将数据插入数据库之前,我已经对字符进行了转义以防止SQL注入。还需要做什么呢?

5个回答

10

XSS主要是关于HTML转义(*). 无论从数据库、直接从用户输入、从文件还是从其他地方获得的纯文本字符串,只要将其放入HTML页面中,就需要对其进行转义。

最小化的HTML转义是将所有的&符号转换为&amp;,所有的<符号转换为&lt;。当您将某些内容放入属性值时,还需要对用于分隔属性的引号字符进行转义,通常使用的是"变为&quot;。总是转义双引号(&quot;)和单引号撇号(&#39;)不会有任何问题,有些人还会将>转义为&gt;,虽然这仅在XHTML的一个角落案例中才是必需的。

任何一个好的面向Web的语言都应该提供一个函数来完成这个任务。例如,在PHP中它是htmlspecialchars()

<p> Hello, <?php htmlspecialchars($name); ?>! </p>

在Smarty模板中,它是escape修饰符:

<p> Hello, {$name|escape:'html'}! </p>

通常情况下,95%的情况都需要HTML转义(相对于允许原始HTML标记的情况比较罕见),所以这应该是默认设置。新一代的模板语言已经认识到,将HTML转义设为选择性开启会导致无尽的XSS漏洞,因此默认情况下进行HTML转义。

您可以通过更改默认修饰符html来使Smarty表现得像这样。(除非你真的知道自己在做什么,否则不要使用他们建议的htmlall,否则会破坏所有非ASCII字符。)

无论如何,千万不要陷入常见的PHP错误中,即在处理输入之前或将其放入数据库之前对其进行HTML转义或“净化”以供HTML使用。这是执行输出阶段编码的错误位置,会引发各种问题。如果要验证输入以确保它符合特定应用程序的要求,则可以这样做,但在此阶段清除或转义“特殊”字符是不适当的。

*:其他XSS方面的问题出现在以下情况:(a)实际上您想允许用户发布HTML,在这种情况下,您需要将其削减到可接受的元素和属性,这是一个复杂的过程,通常由HTML Purifier之类的库完成,即使如此,也可能会出现漏洞。替代方案可能会更简单。 (b)当您允许用户上传文件时,这是非常难以保证安全的。


1
关于SQL注入,仅仅转义是不够的 - 应该尽可能使用数据访问库和参数化查询。
对于XSS(跨站脚本攻击),首先要对输出的数据进行HTML编码。同样,反XSS库是你的朋友。
目前的一种方法是只允许非常有限的标签,并在过程中进行清理(白名单+清理)。

@shahinkian - 看起来是一个很好的用于防止SQL注入的工具。 - Oded
@Oded:我建议使用白名单策略和非HTML格式,例如BBCode。 - Steven Sudit
2
不要让人们感到不必要的恐慌。如果一直这样做,转义绝对足以防止 SQL 注入。只是看起来很丑陋。 - Thorarin
2
@Thorarin: 我强烈建议我们不要依赖转义。你可以争辩说“只要始终如一地执行”,就足够了,但并不总是能始终如一地执行,即使那样做了,也并不总是足够的。(例如,你不能将看似数字值的内容进行转义,也不能可靠地避免所有边缘情况,比如嵌入的NULs。) - Steven Sudit
2
我认为将数字值转换为字符值可能存在一些问题。至少对于MSSQL而言,它会影响索引的使用(现在是错误类型),或在某些情况下会导致类型转换异常。个人而言,我总是更愿意将参数化的责任放在一个库(比如一个数据库访问库)上,这个库被很多人使用,而不是自己编写。 - Eric Tuttleman
显示剩余8条评论

1

您需要确保人们无法在评论中发布JavaScript代码或可怕的HTML。我建议您禁止除非非常基本的标记之外的任何内容。

如果评论不应包含任何标记,则执行

echo htmlspecialchars($commentText);

这应该足够了,但它非常粗糙。更好的方法是在将其放入数据库之前对所有输入进行清理。PHP strip_tags() 函数可以帮助您入手。

如果您想允许 HTML 注释,但又要保证安全,可以尝试使用 HTML Purifier


1
我认为在未通知用户的情况下不应该删除用户数据。只需出现错误并说明不允许这样做。 - Joe Phillips
@d03boy:我部分同意,但你可以使用相同的函数来实现。对输入进行清理并与原始输入进行比较。如果不同,则显示错误消息。 - Thorarin

1

在将数据放入数据库之前,您不应修改用户输入的数据。修改应在输出到网站时进行。您不想丢失原始数据。

在将其输出到网站时,您需要使用类似于htmlspecialchars("my output & stuff", ENT_QUOTES, 'UTF-8')的东西将特殊字符转义为HTML代码--确保指定您正在使用的字符集。这个字符串将被翻译成my output &amp; stuff供浏览器阅读。


显然,你只考虑了跨站脚本攻击(XSS),而没有考虑SQL注入! - user388690
@jsd911 这是一个关于 XSS 的问题,所以我只限制了我的信息在 XSS 上... SQL 注入是另一个话题。 - Joe Phillips

0

防止 SQL 注入的最佳方法就是不要使用接受用户输入的动态 SQL。相反,将输入作为参数传递;这样它将被强类型化,无法注入代码。


我认为这非常相关,因为shahinkian希望使他们的代码更安全,但承认使用了一个方法,委婉地说,并不是最佳实践。 - Steven Sudit
好的,我误读了他的问题。请编辑您的答案,以便我可以取消我的负评。 - Joe Phillips
@d03boy,嘿,别担心。那只是一个离题的评论而已。 - tloflin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接