用PHP清理用户输入的最佳方法是什么?




security xss (14)

不,那里没有。

首先,SQL注入是一个输入过滤问题,而XSS是一个输出转义 - 所以你甚至不会在代码生命周期中同时执行这两个操作。

基本经验法则

  • 对于SQL查询,绑定参数(与PDO一样)或对查询变量(如mysql_real_escape_string() )使用驱动程序本机转义函数
  • 使用strip_tags()过滤掉不需要的HTML
  • 使用htmlspecialchars()转义所有其他输出,并在此注意第二个和第三个参数。

是否有一个catchall函数可以很好地处理SQL注入和XSS攻击的用户输入,同时还允许某些类型的html标记?



Answer #2

不可以。一般来说,如果没有任何关于它的用途的上下文来过滤数据。 有时候你会希望把SQL查询作为输入,有时候你会想把HTML作为输入。

您需要在白名单上过滤输入 - 确保数据符合您的预期。 然后,在使用它之前,您需要将其转义出来,具体取决于您使用它的上下文。

SQL转义数据的过程 - 防止SQL注入 - 与转义(X)HTML数据的过程非常不同,以防止XSS。


Answer #3

有一个过滤器扩展( howto-linkmanual ),它对所有GPC变量都能很好地工作。 这不是一个神奇的事情,但你仍然必须使用它。


Answer #4

你在这里描述的是两个不同的问题:

  1. 消毒/过滤用户输入数据。
  2. 转义输出。

1)用户输入应始终被认为是不好的。

使用预准备语句或/和使用mysql_real_escape_string进行筛选绝对是必须的。 PHP还内置了filter_input,这是一个很好的开始。

2)这是一个很大的话题,它取决于输出数据的上下文。 对于HTML,有一些解决方案,例如htmlpurifier。 作为一个经验法则,总是逃避你输出的任何东西。

这两个问题都非常大,无法在单个帖子中进行讨论,但是有很多帖子会详细介绍:

方法PHP输出

更安全的PHP输出


Answer #5

避免输入和转义数据消毒错误的最简单方法是使用像SymfonyNette等PHP框架或框架的一部分(模板引擎,数据库层,ORM)。

Twig或Latte这样的模板引擎默认情况下会输出转义 - 如果您已根据上下文(网页的HTML或Javascript部分)正确地转义了输出,则无需手动解决。

框架自动清理输入,你不应该直接使用$ _POST,$ _GET或$ _SESSION变量,而是通过路由,会话处理等机制。

对于数据库(模型)层,有像Doctrine这样的ORM框架,或者像Nette数据库一样包装PDO。

您可以在这里阅读更多关于它的信息 - 什么是软件框架?


Answer #6

你从不消毒输入。

你总是消毒输出。

将适用于数据的转换应用于SQL语句中,与包含在HTML中的数据完全不同,与申请包含在Javascript中的应用程序完全不同于您申请包含在LDIF中的应用程序完全不同于你申请加入CSS的申请与申请加入电子邮件的申请完全不同。

通过一切手段验证输入 - 决定是否应该接受它进行进一步处理或告诉用户它是不可接受的。 但是,在它将要离开PHP土地之前,不要对数据的表示进行任何更改。

很久以前,有人试图发明一种适合所有数据转义的机制,并且我们最终得到了“ magic_quotes ”,它没有正确地转义所有输出目标的数据,导致不同的安装需要不同的代码才能工作。


Answer #7

不要试图通过清理输入数据来防止SQL注入。

相反, 不要让数据用于创建您的SQL代码 。 使用准备好的语句(即使用模板查询中的参数)使用绑定变量。 这是保证防止SQL注入的唯一方法。

有关防止SQL注入的更多信息,请参阅我的网站http://bobby-tables.com/


Answer #8

没有传递函数,因为需要解决多个问题。

  1. SQL注入 - 今天,一般来说,每个PHP项目都应该使用通过PHP数据对象(PDO)准备好的语句作为最佳实践, 从而避免错误报价以及针对注入的全功能解决方案 。 它也是访问数据库的最灵活和最安全的方式。

    查看(唯一适当的)PDO教程 ,了解您需要了解的有关PDO的几乎所有内容。 (诚​​挚感谢顶级贡献者@YourCommonSense对这个主题的极好资源。)

  2. XSS - 在...中清理数据

    • HTML净化器已经存在了很长时间,并且仍在积极更新。 您可以使用它来消毒恶意输入,同时仍然允许使用慷慨且可配置的标记白名单。 与许多所见即所得的编辑器很好地协作,但对于某些使用情况可能会很重。

    • 在其他情况下,我们根本不想接受HTML / Javascript,我发现这个简单的函数很有用(并已通过了针对XSS的多重审核):

      /* Prevent XSS input */ function sanitizeXSS () { $_GET = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING); $_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING); $_REQUEST = (array)$_POST + (array)$_GET + (array)$_REQUEST; }

  3. XSS - 在数据出口前对数据进行净化......除非您保证数据在添加到数据库之前已经过正确的清理,您需要在将数据显示给用户之前对其进行清理,我们可以利用这些有用的PHP函数:

    • 当您调用echoprint来显示用户提供的值时,请使用htmlspecialchars除非数据已经过适当的安全清理并且可以显示HTML。
    • json_encode是从PHP到Javascript提供用户提供的值的安全方式
  4. 你使用exec()system()函数调用外部shell命令,还是使用backtick操作符? 如果是这样,除了SQL注入和XSS,你可能还有一个额外的问题需要解决,即在你的服务器上运行恶意命令的用户 。 如果您想要转义整个命令或使用escapeshellarg来转义单个参数,则需要使用escapeshellcmd


Answer #9

如果你使用的是PostgreSQL,PHP的输入可以用pg_escape_string()

 $username = pg_escape_string($_POST['username']);

从文档( http://php.net/manual/es/function.pg-escape-string.php ):

pg_escape_string()转义一个查询数据库的字符串。 它以PostgreSQL格式返回一个不带引号的转义字符串。


Answer #10

只是想在输出转义的主题上加上一点,如果你使用php DOMDocument来创建你的html输出,它会自动在正确的上下文中转义。 属性(value =“”)和<span>的内部文本不相等。 为了避免XSS,请阅读: OWASP XSS预防备忘单


Answer #11

用PHP清理用户输入的最佳BASIC方法:


    function sanitizeString($var)
    {
        $var = stripslashes($var);
        $var = strip_tags($var);
        $var = htmlentities($var);
        return $var;
    }

    function sanitizeMySQL($connection, $var)
    {
        $var = $connection->real_escape_string($var);
        $var = sanitizeString($var);
        return $var;
    }

Answer #12

用户输入可以被过滤是一种常见的误解。 PHP甚至有一个(现在被弃用的)“功能”,称为魔术引号,建立在这个想法上。 这是无稽之谈。 忘记过滤(或清洁,或任何人称之为)。

为了避免问题,你应该做什么很简单:当你在外部代码中嵌入一个字符串时,你必须根据该语言的规则来逃避它。 例如,如果您在某些针对MySql的SQL中嵌入字符串,则必须为此使用MySql函数( mysqli_real_escape_string )来转义该字符串。 (或者,在数据库的情况下,如果可能,使用准备好的语句是一种更好的方法)

另一个例子是HTML:如果你在HTML标记中嵌入字符串,你必须使用htmlspecialchars来转义它。 这意味着每个echoprint语句都应该使用htmlspecialchars

第三个例子可以是shell命令:如果要将字符串(如参数)嵌入到外部命令中,并使用exec调用它们,则必须使用escapeshellcmdescapeshellarg

等等等等 ...

您需要主动过滤数据的唯一情况是,您是否接受预先格式化的输入。 例如。 如果你让你的用户发布HTML标记,你打算在网站上显示。 但是,您应该明智地避免这种情况,因为无论您如何过滤它,它总会是一个潜在的安全漏洞。


Answer #13

要解决XSS问题,请查看HTML Purifier 。 这是相当可配置的,并有一个体面的记录。

至于SQL注入攻击,请确保检查用户输入,然后通过mysql_real_escape_string()运行它。 但是,该函数不会击败所有注入攻击,因此在将数据转储到查询字符串之前检查数据非常重要。

更好的解决方案是使用准备好的语句。 PDO库和mysqli扩展支持这些。





user-input