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

信息安全 php xss 数据验证
2021-08-25 01:04:19

这些是我在用户提交数据时所做的事情:

  1. substr 如果发现多余的字符。
  2. htmlspecialchars()+ ENT_QUOTES+ UTF-8
  3. str_replace '<' '>' 在用户输入中

还有哪些事情需要做?

4个回答

“消毒”是一个无用且具有误导性的术语。这里有两种不同的动物:

  1. 输出转义。这是一个输出阶段的问题当您将变量字符串注入到具有环绕语法的较大字符串中时,您必须处理注入的字符串以使其符合该语法的要求。该处理的具体内容取决于上下文:如果您将文本放入 HTML,则必须在制作 HTML 时对该文本进行 HTML 转义。如果将文本放入 SQL 查询中,则必须在创建查询时对文本进行 SQL 转义。(*)

  2. 输入验证。这是一个输入阶段的问题,确保用户输入在数据项可接受的可能值范围内。这主要是一个业务规则问题,需要逐个字段地考虑,尽管有一些类型的验证对几乎所有输入字段都有意义(主要检查控制字符)。

输入验证确实具有安全影响,因为当您在输出转义时出错时,它可以减轻损害。但是仅仅依靠输入验证作为你唯一的文本处理措施是不够的,因为你总是需要允许用户使用一些在某些语法或其他语法中特殊的字符。您将希望能够fish & chips在您的数据库中拥有一个关于和客户的网页,名为O'Reilly.

“消毒”混淆了这两个概念,并鼓励您在同一阶段解决它们,这永远无法始终如一地发挥作用。一个常见的反模式是对所有输入进行 HTML 转义。但是您不知道每个输入元素是否会在该输入处理阶段输出到 HTML(并且仅输出到 HTML)。如果你这样做:

  • 您最终会在数据库中获得 HTML 编码的材料,如果没有实体引用的阻碍,就无法对其进行切割和处理;

  • 如果您需要从不是 HTML 的数据中创建内容,例如发送电子邮件或编写一些 CSV,那么您的文本会很丑陋;

  • 如果您从任何其他来源获取数据库中的内容,它可能不是 HTML 转义的,因此将其直接输出到页面仍然会给您带来 XSS 漏洞。

“消毒”作为一个概念应该被火烧毁,然后被淹死,切成小块,再被更多的火烧毁。

(*: 在这两种情况下,最好选择一种隐式为您进行处理的方法,这样您就不会弄错:使用默认转义输出的 HTML 模板语言,以及使用参数化查询的数据访问层或对象-关系映射。对于其他类型的转义也是如此:更喜欢符合标准的 XML 序列化程序而不是手动 XML 转义,使用标准 JSON 序列化程序将数据传递给 JavaScript,等等。)

如果发现超过有限的值,则 substr。

你的意思是截断太长的输入字符串?这可以作为一种输入验证形式,您的业务规则有正当理由限制输入的长度。但是,如果您的输入字符串过长,您可能更愿意向用户返回错误,因为取决于它是哪个字段,可能不适合悄悄地丢弃数据。

htmlspecialchars() + ent_quotes + UTF-8

这是输出转义。在将它们放入 HTML 时对值执行此操作,而不是在输入时执行此操作。如果您使用的是原生 PHP 模板,您可能希望为自己定义一个快捷方式以使其更快地输入,例如:

function h($s) {
    echo htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
}
...

<p>Hello, <?php h($user['name']); ?>!</p>

str_replace< >用户输入

做什么的?如果您正确地进行 HTML 转义,则这些字符非常好,除非您的业务规则另有说明,否则包含在字段中可能非常有效 - 就像我在此注释框中键入 SO 时这两个字符都是有效的。

当然,您可能希望在特定字段的输入验证中禁止它们——您不希望它们出现在电话号码或电子邮件地址中。

我使用 OWASP PHP 过滤器。它们非常易于使用且有效。

在此处查看OWASP PHP 过滤器

源代码具有高度可读性。里面有很多惨痛的教训。

由于这是多年前的一个问题,因此有些事情会发生变化,并且外部链接通常会折叠,因为站点不维护或处理其他站点中可能存在的链接。

所以继续前进,PHP 已经进步了一点,许多人询问有关清理输入的问题,但到目前为止,它的使用还很少filter_var,虽然从我的阅读来看,它并不完美,二进制安全。

因此,您会得到一个电子邮件地址,除非您在应该与 PHP 结合使用时不使用 HTML5,否则您filter_var的站点将比编写例程来清理不使用 HTML5 输入的输入的人更安全。为不兼容 HTML5 的浏览器编写向后兼容的代码完全没有意义,而且会浪费您的资源和时间。

另一个安全问题是 $_GET 和 $_POST 的值是易变的,并且可以在外部从好数据更改为坏数据,因此任何使用它们并将清理后的输入传回给它们的清理例程都是成熟的麻烦... $_REQUEST 数组更安全,它一旦设置在您的安全数组中,就无法更改,因此通过将输入和 filter_var 放入安全数组来填充您的安全数组。

我如何清理输入类似于以下内容......

$someSafeArray = array(
        "thefield"=>FILTER_SANITIZE_STRING,
        "theNumberfield"=>FILTER_SANITIZE_NUMBER,
        "theEmailfield"=>FILTER_SANITIZE_EMAIL
        );
foreach( $someSafeArray as $fld=>&$val)
    $val = filter_var( trim( $_REQUEST[$fld] ), $val );

因此,这将返回所有字段(来自键),然后将经过清理的输入放入安全数组中这些键的值中。

这意味着我使用白名单(数组)的键只接受我指定为有效字段的输入。我见过太多人提供接受任何输入的“动态”表单处理器,不!您应该只接受您的代码/表单旨在处理的数据流。

SALT 你的页面,你的接收表单可以重新计算正确的哈希值,以检查你的表单是由服务器发出的,EMPTY 字段,我至少包含一个只读的空白字段,像哈希字段一样隐藏,但目的是确定无论是否推送表单,机器人都会用数据填充所有字段以尝试打开页面。

所以用几个虚拟字段来吸引你的页面,比如......

<input name="userlogin" type="hidden" value="" readonly />
<input name="empty" type="hidden" value="" readonly />

如果表单到达您的服务器时在任一输入的值字段中包含某些内容,您也可以停止任何表单处理并记录用户 IP 并阻止他们,因为他们要么是机器人,要么是黑客。

注入不仅是一个 SQL 问题,它还是一个 PHP 页面问题,因此请注意您接受哪些字段、接受哪些字段salt以及bait您的表单使用并操作白名单。

停止使用 GET 传递控制参数,使用会话 cookie,因为这减少了脚本的输入,如果我使用 GET 类型的 URL,那么它仅用于颠覆性策略,并允许监视用户将变量插入 URL 和其他东西尝试破解。

自从引入 filter_var 函数之前,我一直在使用这样的过程,我在不需要数据库来验证传入页面的情况下对页面进行加盐,这是所谓的专业人员反复告诉我的事情是不可能的,好吧我唯一要说的是“如果您能够跳出样板思考。(框)”并且足够简单以阻止黑客攻击,保护您的表单页面。

我个人永远不会 str_replace on <and >,只是在用户输入上去除标签html 特殊字符html 实体编码mysql_real_escape_string等。

您需要考虑的是如何表示数据?

  • 它会在前端输出吗?
  • 它进入数据库了吗?
  • 它会在前端的 Javascript 中使用吗?
  • 包含文件怎么样?

如果它进入前端,那么您需要对它进行 htmlentities 和 strip_tags imo,这样您就可以确保它们不会尝试执行任何不需要的代码。

此外,剥离斜线是一个很大的考虑因素,我最近在 WP Platinum SEO 插件中发现了一个 XSS,您可以通过 $_GET['s'] 参数将所有内容编码为转义十六进制代码(\\x41 =一个)。

如果要将数据输入数据库,请查看PDO 准备查询以及mysql_real_escape_string这应该可以很好地保护您的数据库输入。

如果您使用用户输入来请求文件,请确保它不易受到Poison Null Byte攻击,并且在我看来,始终剥离文件包含的所有斜杠,以确保它们无法访问所需的位置。我还建议在您的 php.ini 文件中关闭allow_url_include / allow_url_fopen 。

我希望这有帮助!