通过 PHP 在 GET 中清理用户数据

Posted

技术标签:

【中文标题】通过 PHP 在 GET 中清理用户数据【英文标题】:Sanitizing user's data in GET by PHP 【发布时间】:2010-11-21 19:40:50 【问题描述】:

如何通过 PHP 清理 $_GET 变量中的数据?

我只清理了strip_tags GET 中的一个变量。 我不确定是否应该对所有内容进行清理,因为上次将数据放入 Postgres 时,使用pg_prepare 最容易解决问题。

【问题讨论】:

清理以避免 SQL 注入或 XSS 攻击? 【参考方案1】:

如何通过 php 清理 $_GET 变量中的数据?

清理 $_GET 中的数据。这是 PHP 脚本中常用的方法,但它是完全错误的*。

您的所有变量都应保持纯文本形式,直到您将它们嵌入到另一种类型的字符串中。没有一种形式的转义或“清理”可以涵盖您可能将值嵌入其中的所有可能类型的字符串。

因此,如果您将字符串嵌入到 SQL 查询中,则需要在退出时对其进行转义:

$sql= "SELECT * FROM accounts WHERE username='".pg_escape_string($_GET['username'])."'";

如果您要将字符串吐出到 html 中,则需要将其转义:

Cannot log in as <?php echo(htmlspecialchars($_GET['username'], ENT_QUOTES)) ?>.

如果您按照不知道自己在做什么的人的建议,在开始时对 $_GET 数组执行了这两个转义步骤:

$_GET['username']= htmlspecialchars(pg_escape_string($_GET['username']));

然后,当您的用户名中有“&”时,它会在您的数据库中神秘地变成“&”,如果您的用户名中有撇号,它会在页面上变成两个撇号。然后,当您有一个包含这些字符的表单时,很容易在编辑它们时出现双重转义,这就是为什么这么多糟糕的 PHP CMS 最终会出现诸如“O\\\\ 的新书”之类的损坏文章标题的原因\\\\\\\\\\\\\\\'赖利”。

当然,每次发送变量时都要记住 pg_escape_string 或 mysql_real_escape_string 和 htmlspecialchars 有点乏味,这就是为什么每个人都想(不正确地)在脚本开头的一个地方这样做。对于 HTML 输出,您至少可以通过定义一个短名称的函数来节省一些输入,该函数执行 echo(htmlspecialchars(...))。

对于 SQL,最好使用参数化查询。对于 Postgres,有 pg_query_params。或者实际上,正如您提到的那样准备好的陈述(尽管我个人认为它们不太容易管理)。无论哪种方式,您都可以忘记“清理”或转义 SQL,但如果您嵌入其他类型的字符串(包括 HTML),您仍然必须转义。

strip_tags() 不是处理 HTML 显示输入的好方法。过去它存在安全问题,因为浏览器解析器实际上对标签的解释比您想象的要复杂得多。 htmlspecialchars() 几乎总是适合使用,因此如果有人输入小于号,他们实际上会得到一个字面的小于号,并且不会发现一半的文本神秘地消失了。

(*: 无论如何,作为解决注入问题的一般方法。当然,在特定字段上值得进行特定于域的检查,并且您可以执行一些有用的清理任务,例如从提交的值中删除所有控制字符。但这不是大多数 PHP 编码人员所说的清理的意思。)

【讨论】:

能否请您解释一下您的意思是什么如果您嵌入其他类型的字符串(包括 HTML),您仍然必须转义你的意思是当我使用准备好的语句时,我不需要转义我放入数据库的用户名和电子邮件? - 我只显示从数据库中获取的 HTMLL 内的用户的用户名。您的回答表明我需要 pg_espace_string 到用户名。 否:要输出到 SQL 字符串,您使用 SQL 转义(或让参数化/准备好的语句自动为您执行此操作 — 但不能同时使用两者)。为了输出到 HTML,您使用 HTML 转义(使用 htmlspecialchars)。切勿将 HTML 转义文本放在 SQL 字符串中,或​​将 SQL 转义文本放在 HTML 页面中。【参考方案2】:

如果您正在谈论清理输出,我建议您将内容以完整的、未转义的形式存储在数据库中,然后在回显数据时将其转义(htmlspecialchars 或其他内容),这样就可以了更多输出选项。有关清理/转义数据库内容的讨论,请参阅 this question。

在 postgres 中存储方面,在查询中的每个变量上使用pg_escape_string,以转义引号,并且通常可以防止 SQL 注入。

编辑:

我在数据库中存储数据然后检索它的通常步骤是:

    调用数据库数据转义函数(pg_escape_string、mysql_escape_string 等),以转义查询中使用的每个传入 $_GET 变量。请注意,使用这些函数而不是添加斜杠会导致存储在数据库中时文本中没有多余的斜杠。

    当您从数据库中取回数据时,您可以对任何输出数据使用 htmlspecialchars,无需使用斜杠,因为不应有多余的斜杠。

【讨论】:

如果您为用户提供转义数据,他会看到斜线。 您使用哪个函数让用户再次读取数据? 您可以使用 stripslashes (uk2.php.net/stripslashes) 从字符串中删除斜杠。 是否有任何系统范围的选项可以在变量 $_GET$_POST 中清理我的数据,而无需将 htmlspecialvarsstripslashes -statements 放在每个状态? 不,恐怕不会。为什么你需要对传入的数据做stripslashes?你有打开魔术引号吗? 如在数据库中存储一个数组?序列化数组(us2.php.net/manual/en/function.serialize.php),然后在其上调用 pg_escape_string。 (这将为您提供一个表示数组的字符串,您可以将其安全地存储在数据库中。检索值时,对字符串使用反序列化函数将其转回数组。【参考方案3】:

您必须清理所有请求,而不仅仅是 POST 为 GET。

您可以使用函数htmlentities(),函数preg_replace() 与正则表达式,或通过强制转换过滤:

<?
$id = (int)$_GET['id'];
?>

【讨论】:

我同意你的观点,所有请求都必须被分隔。但是,如果您使用pg_prepare,那么我认为您不需要函数htmlentitiies,因为pg_prepare 会清理数据。 不要使用正则表达式来清理输出 - 你一定会错过一些东西,并意外暴露 XSS 漏洞 - 有很好的库可以进行自定义输出清理 (htmlpurifier.org) 马西:那是错误和危险的。 pg_prepare 处理 SQL 转义。它与 HTML 转义没有任何关系,并且不会以任何方式保护您免受由杂散' 【参考方案4】:

根据输入的去向对输入进行清理。

如果您显示它(在页面上或作为输入字段的值),请使用htmlspecialchars 和/或str_replace。 如果您将其用作其他类型,请强制转换。 如果您将其包含在 SQL 查询中,请使用适当的函数对其进行转义,如果您确实希望将其完全删除(这与转义不同),则可以剥离 html 标签。

对于 POST 甚至数据库中的数据也是如此,因为数据库中的数据通常不应该被转义。

你应该检查两件事:

    输入与 PHP 脚本/输出/数据库表的编码 如果您启用了[magic_quotes_gpc][1],您应该禁用它(只要可以)或stripslashes() GET、POST 和COOKIE 值。 magic_quotes_gpc 已弃用,您应该根据数据的用途来清理您操作的数据。

【讨论】:

【参考方案5】:

使用 PHP 原生函数 filter_var()FILTER_SANITIZE_STRING 过滤器。

示例:https://www.w3schools.com/php/filter_sanitize_string.asp

【讨论】:

以上是关于通过 PHP 在 GET 中清理用户数据的主要内容,如果未能解决你的问题,请参考以下文章

使用 PHP GET 清理字符串以在 href 中使用

在 PHP 中清理用户定义的 CSS

有没有办法通过将 php 保存到数据库中来清理 HTML 代码? [复制]

在 Laravel / PDO 中绑定列

清理用户输入PHP

PHP PDO 清理用户输入