过滤输入,转义输出;还是转义输入,过滤输出?

7

我有一个小的困惑。当我在Google上输入内容时,几乎所有的文章都建议“过滤输入,转义输出”。如果我没有一直混淆转义和过滤这两个术语,那么它应该是相反的。

你会看到很多文章类似于:

$username = htmlentities(htmlspecialchars(strip_tags($_POST['username')));

建议不要过滤输入,而是进行转义(之前我们使用mysql_real_escape_string来进行转义,现在预先准备的语句为我们处理)。我们应该将用户提交的数据原封不动地插入到数据库中,不要使用htmlspecialchars等函数对其进行更改。我们应该始终保留数据库中的原始输入,因此在输入时使用htmlspecialchars是错误的。HTML对数据库来说不会造成伤害。

我们应该过滤输出,以防恶意代码(如html、js等)在浏览器上运行。这被称为XSS过滤,而不是XSS转义。例如,在Laravel 4上,{{{ $var }}}被称为XSS过滤,在用户提交的内容输出时应始终使用它。

如果“过滤输入转义输出”表述正确,为什么不使用mysql_real_filter_string()并将XSS防护称为XSS转义

此外,ircmaxell曾经说过:

过滤并不是为了防止安全漏洞,而是为了不让垃圾填满你的数据库。如果你期望得到一个日期,请确保它看起来至少像是一个日期,然后再将其存储。

这被称为验证,但你不能仅依赖于验证。(特别是在旧版本的PHP上)你需要同时对输入进行转义和验证。过滤可能不用于安全漏洞,但转义是必须的。

好了,这就解决了我的困惑。有人能向我解释一下吗?

4个回答

7

看起来我的困惑很简单。我以为输出层是我们开始使用 echo 的层,例如视图层。

根据 Anthony Ferrara 的说法,当数据离开应用程序时,输出层是数据所在的层,当数据进入应用程序时,输入层就是数据所在的层。

因此,Input 层不仅限于用户提供的内容,还包括从配置文件读取、从文件系统读取、从第三方API检索数据等内容,都被视为 Input

Output 不仅限于视图层上的 echoprint。例如,SQL查询 也算作 output,因为数据离开我们的应用程序并进入数据库的范围。同样地,将数据写入文件也算作输出,执行 shell 命令也算作输出。

因此,基本上,查询数据库就是 Output,而从数据库获取结果就是 Input

如果你这样思考,过滤输入,转义输出 就是正确的。如果有人像我一样困惑,这样讲真的很有道理。


3
首先: htmlentitieshtmlspecialchars 实际上并不是转义字符串,它们是将特定字符转换为 HTML 实体!
  1. First you should take your user input and remove the pseudo/automatic "safety" like magic quotes.

    if (get_magic_quotes_gpc())
    {
        $lastname = stripslashes($_POST['lastname']);
        // ...
    }
    

    This is so you have the "pure" or raw user input.

  2. Then filtering means for example not allowing something like fooBar as an email address!

    if (!my_own_email_validity_check($_POST['email'])) die(); // maybe a bit extreme
    
  3. Afterwards escaping the user input to be stored (eg in your database)

    $city = $mysqli->real_escape_string($city);
    

    Or preferably use PDO, which does it "automaticly" :-)

  4. But the really important part is when displaying that data from your database to the user, to make sure you run it all through htmlspecialchars() since you can't be sure that anything in there is sane!!!

现在有一些不同的意见认为你应该在获得原始数据后立即运行htmlentities,但这会使处理数据变得困难,并且并不是推荐的方法。但是这可能取决于你正在做什么,就像许多事情一样。
因此,总体而言,总结如下:
- 当存储用户输入以免受注入攻击时,需要对其进行转义。 - 当显示已存储的数据以避免XSS攻击时,需要对其进行转换。
另外还有很多不同的命名方式,有时人们会在转义时称其为过滤,或者在通用消毒时称其为转义等等。所以不要被命名所迷惑,只要理解发生了什么,你就没问题了 ;-)
回答你的问题:
它被称为“过滤输入,转义输出”,因为...
- 在这种情况下,“过滤”实际上意味着不允许将“错误”的数据存储到数据库中。(就像第2点,电子邮件验证、邮政编码等可以排除的内容。这些也可能会破坏你之后的数据处理!) - 转义输出旨在防止XSS -> 因此实际上是转换为HTML实体,因此这是一个命名问题。 - 在“过滤输入,转义输出”中,要么不关心转义以防止SQL注入,要么甚至用“过滤”来总结(这将不是正确的术语(依我看),就像你说的一样)
在我看来,问题在于命名不一致。

说实话,这就是我在主题中所说的。 - Aristona
是的,我同意你的观点!我只是按照步骤并命名每一个步骤以便清晰明了。例如,在你提出的问题中,为什么它不叫做“mysql_real_filter_string()”,它当然会转义(escape)而不是过滤(filter)。所以你是正确的!我将编辑我的答案,提供一个真正回答你的问题,而不仅仅是演示... - Levite
3
说实话,Levit说得更好。 - hyphen
我们不能对文本进行修剪、去除标签和转义,然后再插入数据库吗?这样做不正确吗? - Luka
好的,所以在输入时进行过滤/验证/剥离标签/修剪,然后转义...并且从数据库获取数据时始终使用htmlspecialchars utf8? 这是正确的吗? - Luka
显示剩余2条评论

1

过滤输入转义输出可以防止存储不受信任的、注入的坏数据,同时还可以防止跨站点脚本攻击(XSS)。


0

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