我正在尝试提出一个函数,该函数可以传递所有字符串以进行清理。这样,从其中出来的字符串就可以安全地插入数据库了。但是有很多过滤功能,我不确定应该使用/需要哪些功能。
请帮助我填写空白:
function filterThis($string) {
$string = mysql_real_escape_string($string);
$string = htmlentities($string);
etc...
return $string;
}
我正在尝试提出一个函数,该函数可以传递所有字符串以进行清理。这样,从其中出来的字符串就可以安全地插入数据库了。但是有很多过滤功能,我不确定应该使用/需要哪些功能。
请帮助我填写空白:
function filterThis($string) {
$string = mysql_real_escape_string($string);
$string = htmlentities($string);
etc...
return $string;
}
Answers:
您在这里犯了一个错误。哦,不,您选择了正确的PHP函数来使您的数据更安全。没关系。您的错误在于操作顺序以及如何以及在何处使用这些功能。
重要的是要了解在清理和验证用户数据,转义数据进行存储和转义数据进行呈现之间的区别。
用户提交数据时,您需要确保他们提供了期望的内容。
例如,如果您希望输入数字,请 确保提交的数据是数字。你也可以投射用户数据转换为其他类型。最初提交的所有内容都像字符串一样对待,因此将已知数值数据强制为整数或浮点数可以使清理工作变得快捷而轻松。
自由格式的文本字段和文本区域呢?您需要确保在这些字段中没有任何意外。主要是,您需要确保不应包含任何HTML内容的字段实际上不包含HTML。有两种方法可以解决此问题。
首先,您可以尝试使用来转义 HTML输入htmlspecialchars
。你不应该使用htmlentities
中和HTML,因为它还会对重音符号和它认为也需要编码的其他字符进行编码。
其次,您可以尝试删除所有可能的HTML。 strip_tags
既方便又快捷,而且草率。 HTML净化器在剥离所有HTML以及允许通过标记和属性的选择性白名单方面做得更加彻底。
现代PHP版本附带有filter扩展,它提供了一种清理用户输入的综合方法。
确保提交的数据中没有意外内容,只是工作的一半。您还需要尝试确保提交的数据包含您可以实际使用的值。
如果期望数字介于1到10之间,则需要检查该值。如果您正在使用带有微调器和步骤的那些新颖的HTML5-era数字输入之一,请确保提交的数据与步骤一致。
如果该数据来自应该是下拉菜单的数据,请确保提交的值是菜单中显示的值。
满足其他需求的文本输入呢?例如,日期输入应通过strtotime
或DateTime类进行验证。给定的日期应该在您期望的范围之间。电子邮件地址呢?尽管我是is_email库的粉丝,但前面提到的过滤器扩展可以检查地址格式是否正确。
所有其他窗体控件也是如此。有单选按钮吗?根据列表进行验证。有复选框吗?根据列表进行验证。有文件上传吗?确保文件为预期类型,并将文件名视为未过滤的用户数据。
每个现代的浏览器都内置有完整的开发人员工具集,这对任何人操作您的表单来说都是微不足道的。 您的代码应假定用户已完全删除了对表单内容的所有客户端限制!
现在,您已经确保数据采用预期的格式并且仅包含预期的值,接下来您需要担心将数据持久存储到存储中。
每个数据存储机制都有特定的方法来确保对数据进行正确的转义和编码。如果要构建SQL,则可接受的在查询中传递数据的方法是使用带占位符的预备语句。
在PHP中使用大多数SQL数据库的一种更好的方法是PDO扩展。它遵循准备语句的常见模式,将变量绑定到语句,然后将语句和变量发送到服务器。如果您以前没有使用过PDO,那么这里有一个非常不错的面向MySQL的教程。
一些SQL数据库在PHP中具有自己的特殊扩展,包括SQL Server,PostgreSQL和SQLite 3。这些扩展中的每一个都具有准备好的语句支持,该语句支持的执行方式与PDO相同的prepare-bind-execute执行方式。有时,您可能需要使用这些扩展而不是PDO来支持非标准功能或行为。
MySQL还具有自己的PHP扩展。实际上,其中两个。您只想使用一个称为mysqli的版本。旧的“ mysql”扩展名已被弃用,在现代时代使用它并不安全或理智。
我个人不喜欢mysqli。它对准备好的语句执行变量绑定的方式不灵活,使用起来很痛苦。如有疑问,请改用PDO。
如果您不使用SQL数据库存储数据,请查看用于数据库接口的文档,以确定如何安全地通过数据库传递数据。
如果可能,请确保数据库以适当的格式存储数据。将数字存储在数字字段中。将日期存储在日期字段中。将钱存储在十进制字段中,而不是浮点字段中。查看数据库提供的有关如何正确存储不同数据类型的文档。
每次向用户显示数据时,都必须确保安全地转义了数据,除非您知道不应转义。
发出HTML时,几乎应该始终通过传递用户最初提供的任何数据htmlspecialchars
。实际上,唯一不应该做的是,当您知道用户提供了HTML,并且知道已经使用白名单对其进行了清理时。
有时您需要使用PHP生成一些Javascript。Javascript没有与HTML相同的转义规则!通过PHP向Javascript提供用户提供的值的安全方法是通过json_encode
。
数据验证还有许多细微差别。
例如,字符集编码可能是一个巨大的陷阱。您的应用程序应遵循“ 贯穿整个UTF-8 ”中概述的做法。当您将字符串数据视为错误的字符集时,可能会发生假想的攻击。
之前我提到了浏览器调试工具。这些工具也可以用于处理Cookie数据。 Cookies应该被视为不受信任的用户输入。
数据验证和转义只是Web应用程序安全性的一方面。您应该使自己了解Web应用程序攻击方法,以便针对它们建立防御。
<>
,而不是替换其实体中的每个字符
htmlspecialchars
两次电话,因为他在“用户提交数据时”部分和“显示数据时”部分中都提到了这一点。
防止SQL注入的最有效方法是使用PDO
。使用参数化查询,查询与数据分离,从而消除了一阶SQL注入的威胁。
就删除HTML而言,删除HTML strip_tags
可能是最好的主意,因为它只会删除所有内容。 htmlentities
听起来像什么,所以也可行。如果需要解析允许使用的HTML(即,您希望允许某些标签),则应使用成熟的现有解析器,例如HTML Purifier。
数据库输入-如何防止SQL注入
您需要先转义用户输入,然后再将其插入或更新到数据库中。这是一种较旧的方法。您现在想使用参数化查询(可能来自PDO类)。
$mysql['username'] = mysql_real_escape_string($clean['username']);
$sql = "SELECT * FROM userlist WHERE username = '{$mysql['username']}'";
$result = mysql_query($sql);
来自数据库的输出-如何防止XSS(跨站点脚本)
htmlspecialchars()
仅在从数据库输出数据时使用。HTML Purifier也是如此。例:
$html['username'] = htmlspecialchars($clean['username'])
最后...您的要求
我必须指出,如果将PDO对象与参数化查询一起使用(执行此操作的正确方法),那么确实没有简单的方法可以轻松地实现此目的。但是,如果您使用旧的“ mysql”方式,那么这就是您所需要的。
function filterThis($string) {
return mysql_real_escape_string($string);
}
我的5美分。
这里没有人了解mysql_real_escape_string
工作方式。此功能不过滤或“消毒”任何东西。
因此,您不能将此功能用作某些通用过滤器,以免注射。
只有在了解其工作原理和适用范围时,才能使用它。
对于已经写过的类似问题,我有一个答案:
在PHP中,向数据库提交字符串时,我应该使用htmlspecialchars()还是使用正则表达式来处理非法字符?
请单击以获取有关数据库侧安全性的完整说明。
至于htmlentities-Charles正确地告诉您将这些功能分开。
试想一下,您将插入一个由admin生成的数据,该数据将被允许发布HTML。您的功能会破坏它。
虽然我建议不要使用htmlentities。此功能很久以前就已过时。如果你想只更换<
,>
和"
在HTML安全起见字符-使用有意开发用于这一目的的功能-一个用htmlspecialchars()之一。
mysql_real_escape_string
转义字符串中所需的字符。它不是严格的过滤或清理,而是用引号引起来的字符串都不是(每个人都这样做,我几乎从来没有见过关于它的问题)。因此,当我们编写SQL时,没有任何东西可以消毒吗?当然不是。阻止SQL注入的是使用mysql_real_escape_string
。也是用引号引起来的,但是每个人都这样做,并且如果您对所做的事情进行了测试,则最终由于此语法错误而导致SQL语法错误。真正危险的部分用处理mysql_real_escape_string
。
WHERE id = 1
?;)
WHERE my_field = two words
(不带引号)获取语法错误。您的示例很糟糕,因为它既不需要引号,也不需要转义,只需数字检查。我也不是说引号没有用。我说过每个人都使用它们,因此这并不是SQL注入问题的根源。
everyone use them
你可以在这里检查代码。许多人不使用带数字的引号。去搞清楚。请记住,我不在这里讨论您所说的内容,而您没有。我只是在解释基本的数据库安全规则。您最好学习而不是空谈。这里没有人提到引号或强制转换,但是m_r_e_s只是魔术。我在说什么
对于数据库插入,您只需要mysql_real_escape_string
(或使用参数化查询)。通常,您不希望在保存数据之前更改数据,如果使用则会发生这种情况htmlentities
。稍后当您htmlentities
再次运行它以将其显示在网页上的某个位置时,这将导致乱码。
使用htmlentities
当你在网页上的某处显示数据。
有点相关,如果您要在电子邮件中的某处(例如,使用联系表单)发送提交的数据,请确保从标题中将使用的任何数据中删除换行符(例如“发件人:姓名和电子邮件地址,主题等”) )
$input = preg_replace('/\s+/', ' ', $input);
如果您不这样做,垃圾邮件机器人找到您的表单并滥用它只是时间问题,我已经学到了很难的方法。
我总是建议使用像GUMP这样的小型验证包: https //github.com/Wixel/GUMP
围绕这样的库构建所有基本功能,并且几乎不可能忘记卫生条件。“ mysql_real_escape_string”不是进行良好过滤的最佳选择(就像“您的常识”所述),并且,如果您忘记只使用一次,则整个系统将可以通过注入和其他讨厌的攻击进行攻击。
对于所有在这里讨论并依赖mysql_real_escape_string的人,您需要注意该函数在PHP5上已被弃用,而在PHP7上不再存在。
恕我直言,完成此任务的最佳方法是通过使用PDO与数据库交互来使用参数化查询。检查此:https : //phpdelusions.net/pdo_examples/select
始终使用过滤器来处理用户输入。参见http://php.net/manual/es/function.filter-input.php
mysqli_real_escape_string()
中可用。
您可以在类似于以下代码的代码中使用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内容中输出字符串时,htmlentities()用于转换实体中的某些字符。
多数民众赞成在我相信足够的基本秒。它应该阻止所有来自黑客的重大攻击。
对于服务器端安全性,您可能需要在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 ready for db
if(strlen($string) > $dbmax || strlen($string) < $dbmin){
echo "reject_this"; exit();
}
return $string;
}