SQL注入,引号和PHP

4

我很困惑,希望您能帮我澄清一下。最近的匿名者/Lulsec攻击后,我开始质疑我的php/mysql安全性。

所以我想知道,如何保护PHP和Mysql。

问题:有人能为我解释一下,在处理引号方面,什么是最佳实践?

  • 特别是在表单中,我需要某种htmlspecialchars来保护html,对吗?
  • 通过表单可以利用PHP吗?是否需要任何形式的保护?
  • 我应该仅在查询之前使用 real_escape_string 吗?在PHP内部使用它是否有错/不好(请参见 sanitize_post 函数)?

目前我正在使用以下函数。该函数“清理”了所有$_POST和$_GET变量。这样做是否“安全”?

function sanitize_post($array) {
    global $db;
    if(is_array($array)) {
        foreach($array as $key=>$value) {
            if(is_array($array[$key])) {
                $array[$key] = sanitize_post($array[$key]);
            } elseif(is_string($array[$key])) {
                $array[$key] = $db->real_escape_string(strtr(stripslashes(trim($array[$key])), array("'" => '', '"' => '')));
            }
        }            
    } elseif(is_string($array)) {
        $array = $db->real_escape_string(strtr(stripslashes(trim($array)), array("'" => '', '"' => '')));
    }
    return $array;
}

我正在使用PHP 5.3.5和Mysql 5.1.54。谢谢。
7个回答

6

2
是的。使用带有占位符的预处理语句来传递任何不可信输入是目前最佳的实践。 - snap
1
谢谢,我今天学到了新东西。感谢您的回答,绝对是非常好的。然而,由于我必须在几天内上线一个新版本,Tomas Telensky的答案对我来说最有用,短期内能够解决问题。谢谢。 - ptmr.io

6

最佳实践是始终使用预处理语句。这可以防止SQL注入攻击。您可以使用PDO或mysqli来实现。请忘记所有旧的mysql_*函数,它们已经过时且不再建议使用。


3

2

不要浪费精力使用mysql_real_escape_string()或类似的方法。只需使用准备好的语句与PDO,SQL注入是不可能的。


2
不是“不可能的”。创建可注入查询要困难得多,但仍然是可能的。 - Mchl
@Mchl 或许在严格的定义上并不是“不可能”,但实际上它是不可能的。你不会得到比使用预处理语句更好的保护。它实际上是100%的。没有必要通过吹毛求疵来吓唬任何人。 - user428517
我仍然(经过这么多年)坚持认为,预处理语句并非万能药。如果使用它们的人实际上不了解SQL注入的工作原理以及如何使用预处理语句来避免它们,那么他们只会产生虚假的安全感。 - Mchl
我会保持这个看法(经过这么多年),这并不是一个问题。使用预处理语句,你可能会没事的。对于99%的开发人员来说,这已经足够好了。 - user428517
好的,你可能会没问题的 ;) - Mchl
没错,这并没有问题。99%的开发者不需要担心有人尝试进行 SQL 注入攻击,因为他们不会在恶意黑客实际关心的主要网站上工作。 - user428517

2
没有什么像“通用消毒”这样的东西。我们称之为“引用”,因为这就是它的全部意义。
在引用时,您始终会引用某些特定输出的文本,例如:
1. MySQL 查询的字符串值 2. MySQL 查询的 like 表达式 3. HTML 代码 4. JSON 5. MySQL 正则表达式 6. PHP 正则表达式
对于每种情况,您需要不同的引用,因为每种用法都存在于不同的语法上下文中。这也意味着引用不应该在输入到 PHP 中进行,而应在特定输出处进行!这就是为什么类似于 magic_quotes_gpc 的功能是错误的(请务必确保其已关闭!)。
那么,在这些特定情况下,人们会使用什么方法来进行引用?(随时纠正我,可能有更现代的方法,但这些方法对我有效)
1. mysql_real_escape_string($str) 2. mysql_real_escape_string(addcslashes($str, "%_")) 3. htmlspecialchars($str) 4. json_encode() - 仅适用于 utf8!我使用 iso-8859-2 的函数 5. mysql_real_escape_string(addcslashes($str, '^.[]$()|*+?{}')) - 在这种情况下不能使用 preg_quote,因为反斜杠将被转义两次! 6. preg_quote()

我有一个问题,这些解决方案能够防止 SQL 注入等问题吗? - Sarah
mysql_real_escape_string自PHP 5.5.0版本起已被弃用。 应使用MySQLi或PDO_MySQL扩展。 - AID

0

基本工作流程应该是

$data = $_POST['somefield which will go into the database'];

... do data validation ...

if (everything ok) {
    $escaped_data = escape_function($data);
    $sql = " ... query here with $escaped_data ... ";
    do_query($sql);
}

基本上,已经为数据库插入转义的数据应该仅用于数据库插入。当只有2或3个值实际上接近数据库时,预处理所有内容并用db转义值覆盖所有数据是没有意义的。

同样适用于htmlspecialchars。除非数据要发送到HTML类型的显示器,否则不要通过htmlspecialchars发送数据。

不要将数据存储在针对特定目的格式化的DB中,因为如果您需要将数据以其他形式用于某些其他目的,则必须撤消转义。始终在db中存储原始/未格式化的数据。请注意:使用mysql_real_escape_string()和公司完成的转义实际上不会存储在db中。它只是为了确保数据安全地进入数据库。实际存储在db中的是原始的未转义/未引用的数据。一旦它在数据库中,它就是“安全”的。

例如,将转义函数视为转移囚犯的手铐。当犯人在任何一个监狱内时,都不需要手铐。


0

我通常会在变量通过 $_POST(或 $_GET,取决于你使用哪个)进入时使用 PHP 函数 stripslashesstrip_tags,并在查询期间使用 mysql_real_escape_string。(我不确定这是否是“正确”的,但到目前为止它对我起作用了。)您还可以使用 PHP 的 内置验证过滤器 来检查诸如电子邮件地址、URL、数据类型等内容。PDO 据说很好地防止 SQL 注入,但我还没有任何经验。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接