什么是最好的 PHP 输入消毒函数?

我正在尝试创建一个函数,可以将所有字符串传递过去进行消毒。因此,从中产生的字符串对于数据库插入来说是安全的。但是有这么多的 过滤功能在那里,我不知道哪些我应该使用/需要。

请帮我填空:

function filterThis($string) {
$string = mysql_real_escape_string($string);
$string = htmlentities($string);
etc...
return $string;
}
205119 次浏览

这取决于您使用的数据类型。通常最好的选择是使用 mysqli_real_escape_string,但是,例如,您知道不会有 HTML 内容,使用 Strip _ tag 将增加额外的安全性。

您还可以删除您知道不应该允许的字符。

在类似于以下代码的代码中使用 Mysql _ real _ escape _ string ()

$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
mysql_real_escape_string($user),
mysql_real_escape_string($password)
);

正如文档所说,它的目的是转义作为参数传递的字符串中的特殊字符,同时考虑到连接的当前字符集,因此将其放在 Mysql _ query ()中是安全的。文件还补充称:

如果要插入二进制数据,则必须使用此函数。

当您在 HTML 内容中输出一个字符串时,htmltity () 用于转换实体中的一些字符。

防止 SQL 注入的最有效的消毒参量化是使用 PDO。使用参数化查询,查询与数据分离,从而消除了一阶 SQL 注入的威胁。

就删除 HTML 而言,strip_tags可能是删除 HTML 的最佳方法,因为它将删除所有内容。htmlentities听起来像什么就是什么,所以它也可以工作。如果需要解析允许的 HTML (即希望允许 一些标记) ,应该使用成熟的现有解析器,如 HTML 净化器

对于数据库插入,您只需要 mysql_real_escape_string(或使用参数化查询)。通常不希望在保存数据之前更改数据,如果使用 htmlentities,就会发生这种情况。这将导致混乱后来当您运行它通过 htmlentities再次显示它在网页上的某个地方。

当你在网页的某处显示数据时,请使用 htmlentities

有点相关的是,如果你在电子邮件中的某个地方发送提交的数据,比如联系表单,一定要从标题中使用的任何数据(比如发件人: 姓名和电子邮件地址,子集等)中去掉换行符

$input = preg_replace('/\s+/', ' ', $input);

如果你不这样做,它只是一个时间问题的垃圾邮件机器人找到你的形式和滥用它,我已经学到了艰难的道路。

住手!

你在犯一个错误。哦,不,您已经选择了正确的 PHP 函数,使您的数据更加安全。没关系。您的错误是在 行动次序中,以及如何和在哪里使用这些函数。

了解清除和验证用户数据、为存储转义数据和为表示转义数据之间的区别非常重要。

消毒和验证用户数据

当用户提交数据时,您需要确保他们已经提供了您所期望的内容。

消毒和过滤

例如,如果您期望一个数字,确保提交的数据是一个数字。也可以将 转换用户数据转换用户数据分为其他类型。所有提交的内容最初都被当作字符串处理,因此强制将已知数值数据转换为整数或浮点数可以快速而无痛苦地进行消毒。

那么自由格式的文本字段和文本区呢?你得确保这些领域没有什么意外。主要是,您需要确保不应该包含任何 HTML 内容的字段实际上不包含 HTML。有两种方法可以处理这个问题。

首先,您可以使用 htmlspecialchars尝试 逃跑 HTML 输入。您不应该使用 htmlentities来中和 HTML,因为它还将执行重音字符和其他字符的编码,它认为这些字符也需要进行编码。

其次,您可以尝试 移除任何可能的 HTML。strip_tags是快速和容易,但也草率。HTML 净化器在剥离所有 HTML 和允许标记和属性的选择性白名单方面做得更彻底。

现代 PHP 版本附带了 过滤器扩展,它提供了一种全面的方法来净化用户输入。

确认

确保提交的数据没有意外内容只完成了工作的一半。您还需要尝试并确保提交的数据包含可以实际使用的值。

如果您期望的数字介于1和10之间,则需要检查该值。如果您正在使用带有微调器和步骤的新式 HTML5时代数值输入,请确保提交的数据与步骤一致。

如果该数据来自应该是下拉菜单的内容,请确保提交的值是出现在菜单中的值。

那么满足其他需求的文本输入呢?例如,日期输入应该通过 strtotime日期时间类进行验证。给定的日期应该在您期望的范围之间。电子邮件地址呢?前面提到的 过滤器扩展可以检查地址是否格式良好,尽管我是 电子邮件库的粉丝。

对于 所有其他窗体控件也是如此。有无线电按钮吗?根据列表进行验证。有复选框吗?根据列表进行验证。有文件上传吗?确保文件属于预期类型,并将文件名视为未筛选的用户数据。

每个现代浏览器都内置了一套完整的开发工具,这使得任何人都可以轻松地操纵表单。您的代码应该假设用户已经完全取消了对表单内容的所有客户端限制

为存储转义数据

既然已经确保数据采用预期的格式,并且只包含预期的值,那么就需要考虑如何将该数据保存到存储器中。

每个单独的数据存储机制都有一种特定的方法来确保数据被正确地转义和编码。如果您正在构建 SQL,那么在查询中传递数据的公认方法是通过 带占位符的预先准备好的陈述

在 PHP 中使用大多数 SQL 数据库的较好方法之一是 PDO 分机。它遵循 准备一份声明将变量绑定到语句,然后是 将语句和变量发送到服务器的共同模式。如果你在 这里有一个非常好的面向 MySQL 的教程之前没有使用过 PDO。

一些 SQL 数据库在 PHP 中有自己的专业扩展,包括 SQL ServerPostgreSQLSQLite 3。每个扩展都准备了语句支持,其操作方式与 PDO 相同。有时您可能需要使用这些扩展而不是 PDO 来支持非标准特性或行为。

MySQL 也有自己的 PHP 扩展。事实上,有两个。你只想用 Mysqli。旧的“ mysql”扩展一直是 不赞成,在现代使用它既不安全也不理智。

我个人不喜欢 mysqli。它对准备好的语句执行变量绑定的方式是不灵活的,使用起来很麻烦。如有疑问,请改用 PDO。

如果您不使用 SQL 数据库来存储数据,请检查正在使用的数据库接口的文档,以确定如何安全地通过该接口传递数据。

如果可能,请确保数据库以适当的格式存储数据。将数字存储在数字字段中。将日期存储在日期字段中。将钱存储在小数字段中,而不是浮点数字段中。查看数据库提供的有关如何正确存储不同数据类型的文档。

演示文稿转义数据

每次向用户显示数据时,必须确保数据已安全转义,除非 知道表示不应转义该数据。

在发出 HTML 时,您应该几乎总是传递最初通过 htmlspecialchars由用户提供的任何数据。事实上,您唯一不应该这样做的时候是当您的 知道用户提供了 HTML,并且您的 知道已经使用白名单对其进行了消毒。

有时需要使用 PHP 生成一些 Javascript。Javascript 没有与 HTML 相同的转义规则!通过 PHP 向 Javascript 提供用户提供的值的安全方法是通过 json_encode

还有更多

数据验证还有更多的细微差别。

例如,字符集编码可能是一个巨大的陷阱。您的应用程序应遵循“ UTF-8完全通过”中概述的实践。当您将字符串数据视为错误的字符集时,可能会发生一些假设的攻击。

前面我提到了浏览器调试工具。这些工具也可以用来操作 Cookie 数据。

数据验证和转义只是 Web 应用程序安全性的一个方面。您应该让自己意识到 网络应用程序攻击方法,这样您就可以构建对抗它们的防御系统。

数据库输入-如何防止 SQL 注入

  1. 例如,检查以确保整数类型的数据是有效的,方法是确保它实际上是一个整数
    • 对于非字符串,您需要确保数据实际上是正确的类型
    • 对于字符串,您需要确保字符串在查询中被引号包围(显然,否则它甚至不会工作)
  2. 在避免 SQL 注入(mysql _ real _ escape _ string 或参数化查询)的同时,向数据库输入值
  3. 当从数据库中检索值时,确保不会将 HTML 注入到页面中(htmlspecalchars) ,从而避免跨网站脚本攻击

在将用户输入插入或更新到数据库之前,需要转义用户输入。这里有一个更古老的方法。您现在可能希望使用参数化查询(可能来自 PDO 类)。

$mysql['username'] = mysql_real_escape_string($clean['username']);
$sql = "SELECT * FROM userlist WHERE username = '{$mysql['username']}'";
$result = mysql_query($sql);

从数据库输出-如何防止 XSS (跨网站脚本)

只有在从数据库输出数据时才使用 htmlspecialchars()。 HTML 净化器也是如此。示例:

$html['username'] = htmlspecialchars($clean['username'])

最后... 你要的东西

我必须指出,如果您使用带有参数化查询的 PDO 对象(正确的方法) ,那么实际上没有容易实现这一点的简单方法。但是如果您使用旧的“ mysql”方式,那么这就是您所需要的。

function filterThis($string) {
return mysql_real_escape_string($string);
}

我的五分钱。

这里没有人了解 mysql_real_escape_string的工作方式
因此,您不能使用这个函数作为一些通用的过滤器,将节省您从注入。
只有当你了解它是如何工作的以及它适用的地方时,你才能使用它。

对于我已经写过的非常类似的问题,我已经有了答案: 在 PHP 中,当向数据库提交字符串时,我应该使用 htmlspecalchars ()来处理非法字符,还是使用正则表达式?
请单击以获取关于数据库端安全的完整解释。

至于 htmltity-Charles 正确地告诉你要分离这些函数。
想象一下,您要插入一个由管理员生成的数据,管理员可以发布 HTML。你的功能会破坏它。

不过我建议你不要这么做。这个功能早就过时了。如果为了 HTML 的安全只想替换 <>"字符,那么使用为此目的而特意开发的函数—— Htmlspecalchars ()字符。

我总是建议使用像 GUMP 这样的小型验证包: Https://github.com/wixel/gump

像这样围绕一个库构建所有基本功能,几乎是不可能忘记卫生设施的。 “ mysql _ real _ escape _ string”并不是良好过滤的最佳选择(就像“你的常识”解释的那样)——如果你忘记只使用一次,你的整个系统将会受到注射和其他恶意攻击的攻击。

对于在这里讨论和依赖 mysql _ real _ escape _ string 的所有人,您需要注意,该函数在 PHP5上已被弃用,在 PHP7上不再存在。

恕我直言,完成这项任务的最佳方法是通过使用 PDO 与数据库进行交互,使用参数化查询。 检查这个: < a href = “ https://phpdelusions.net/pdo _ example/select”rel = “ nofollow norefrer”> https://phpdelusions.net/pdo_examples/select

始终使用过滤器处理用户输入。 请参阅 < a href = “ http://php.net/Manual/es/function. filter-input.php”rel = “ nofollow norefrer”> http://php.net/manual/es/function.filter-input.php

这是我目前练习的方法之一,

  1. 植入 csrf 和 salt tempt 令牌以及用户要发出的请求,并从请求中一起验证它们。请参阅此处
  2. 确保不要过分依赖客户端 cookie,并确保练习使用服务器端会话
  3. 当解析任何数据时,确保只接受数据类型和传输方法(如 POST 和 GET)
  4. 确保对 webApp/App 使用 SSL
  5. 确保还生成基于时间的会话请求来有意限制垃圾邮件请求。
  6. 当将数据解析到服务器时,确保在所需的数据方法(如 json、 html 等)中验证请求。.然后继续
  7. 使用转义类型从输入中转义所有非法属性... ... 例如 realescape estring。
  8. 之后,验证只有清洁格式的数据类型,你想从用户。
    例如:
    - 电子邮件: 检查输入是否采用有效的电子邮件格式
    - text/string: 只检查输入是否为文本格式(string)
    - number: 检查只允许数字格式。
    请参考 php 门户中的 php 输入验证库
    - 确认后,请使用准备好的 SQL 语句/PDO 进行操作。
    - 完成后,确保退出并终止连接
    - 不要忘记清除输出值一旦完成。

这就是我所相信的足够的基本秒。它应该防止所有主要的攻击从黑客。

为了服务器端的安全性,您可能需要在 apache/htaccess 中设置访问限制和机器人预防以及路由预防。.除了服务器端的系统安全之外,服务器端的安全还有很多工作要做。

您可以从 htaccess apache sec 级别(常见的惯例)学习并获得 sec 的副本

function sanitize($string, $dbmin, $dbmax) {
$string = preg_replace('#[^a-z0-9]#i', '', $string); // Useful for strict cleanse, alphanumeric here
$string = mysqli_real_escape_string($con, $string); // Get it ready for the database
if(strlen($string) > $dbmax ||
strlen($string) < $dbmin) {


echo "reject_this"; exit();
}
return $string;
}

用这个:

$string = htmlspecialchars(strip_tags($_POST['example']));

或者这样:

$string = htmlentities($_POST['example'], ENT_QUOTES, 'UTF-8');

正如您提到的,您正在使用 SQL 消毒,我建议使用 PDO 和准备好的语句。这将极大地改善您的保护,但请做进一步的研究,清理任何用户输入传递给您的 SQL。

若要使用预置语句,请参见下面的示例。你有这个吗?对于这些值,然后用3个字符串‘ sss’绑定它们,这3个字符串被称为 firstname、 lastname 和 email

// prepare and bind

$stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)");

$stmt->bind_param("sss", $firstname, $lastname, $email);