【问题标题】:Does this work to stop sql injections这是否可以阻止 sql 注入
【发布时间】:2011-12-27 16:14:59
【问题描述】:

我一直在使用下面的代码块来阻止 sql 注入。这是我刚开始 php 时有人给我看的东西(不久前)

我把它放在每一页上,就像打开的一样。我想知道它是否有效?我不知道如何测试 sql 注入

<?php

//Start the session

session_start();


//=======================open connection

include ('lib/dbconfig.php');

//===============This stops SQL Injection in POST vars

  foreach ($_POST as $key => $value) {
    $_POST[$key] = mysql_real_escape_string($value);
  }

  foreach ($_GET as $key => $value) {
    $_GET[$key] = mysql_real_escape_string($value);
  }

我的典型插入和更新查询如下所示

$insert = ("'$email','$pw','$company', '$co_description', '$categroy', '$url', '$street', '$suite', '$city', '$state', '$zip', '$phone', '$date', '$actkey'");

mysql_query("INSERT INTO provider (email, pw, company, co_description, category, url, street, suite, city, state, zip, phone, regdate, actkey) VALUES ($insert)") or die ('error ' . mysql_error());

mysql_query("UPDATE coupon SET head='$_POST[head]', fineprint='$_POST[fineprint]', exdate='$exdate', creationdate=NOW() WHERE id='$cid'") or die ('error ' . mysql_error());

【问题讨论】:

  • 看来你的代码没问题,但方法太错误了。自早期 PHP 的结婚时代以来,世界就在进步。使用 PDO/MySQLI。使用参数化查询,使用单个访问点进入您的数据库...
  • 感谢您的回答,请原谅我的无知,但您能否详细说明单个接入点。在我当前的项目中,我访问每个页面上的数据库进行条目和查询。这是不正确的?
  • 我通常有一个类来管理与数据库的连接和低级操作(例如对数据库运行查询并取回结果)。在此之上我还有另一层,负责获取不同格式的请求并将其转换为 SQL,该层也是唯一清理数据的层,我总是使用该类来创建 sql。这样我很确定我不会受到 SQL 注入的影响,如果不是,我只需要在一个地方解决这个问题。

标签: php mysql sql-injection code-injection


【解决方案1】:

这有点有效,但不是最理想的——并非您在 _GET 和 _POST 中收到的所有数据都会进入数据库。有时您可能希望将其显示在页面上,在这种情况下 mysql_real_escape_string 只会受到伤害(相反,您需要 htmlentities)。

我的经验法则是仅在将某些内容放入需要转义的上下文之前立即对其进行转义。

在这种情况下,您最好只使用参数化查询 - 然后会自动为您完成转义。

【讨论】:

  • 酷,我从来没有读过参数化查询,但快速搜索表明我有很多阅读要做。
【解决方案2】:

这并不是为了防止SQL Injection,真正的逃逸方法只是把\加到危险的地方

像 " 或 ' 这样的字符,所以带有 "hi"do'like" 的字符串会变成 "hi\"do\'like\" 所以它是

不那么危险

这种方法并不总是有用的;如果你想显示 tha 转义的内容

页面中的变量只会破坏它并降低可读性

【讨论】:

    【解决方案3】:

    有点。

    mysql_real_escape_string 函数采用给定变量并将其转义以进行 SQL 查询。因此,您可以安全地将字符串附加到查询中,例如

    $safe =  mysql_real_escape_string($unsafe_string);
    $query = 'SELECT * FROM MyTable WHERE Name LIKE "' . $safe . '" LIMIT 1';
    

    它不能保护您免受有人将恶意代码放入该查询以稍后显示(即 XSS 或类似攻击)。因此,如果有人将变量设置为

    // $unsafe_string = '<script src="http://dangerous.org/script.js"></script>'
    $safe =  mysql_real_escape_string($unsafe_string);
    $query = 'UPDATE MyTable SET Name = "' . $safe . '"';
    

    该查询将按您的预期执行,但现在在您打印此人姓名的任何页面上,他的脚本都会执行。

    【讨论】:

    • 谢谢。这是我没有想到的,插入一个完整的脚本链接……现在要学习的东西很多。谢谢你的回答。
    • @Daniel 这是完全错误的说法。 mysql_real_escape_string 不会让任何东西“安全”。
    • @Col.Shrapnel 我想你想说的是,“仅仅因为字符串可以安全地插入 MySQL 查询并不意味着它是安全的。”这正是我试图在这篇文章中传达的内容。声称我所写的内容是完全错误的,这是一种修辞和误导。引用,mysql_real_escape_string "Escapes special characters in a string for use in an SQL statement"。
    • 不。我想说 mysql_real_escape_string 不会使“给定变量”“安全地插入 MySQL 查询”。严格来说,它与“安全”无关。尽管您的后一种说法更正确,但您的回答中的说法完全具有误导性,会导致注入。
    • @Col.Shrapnel 重新措辞澄清。希望没有人会被误导。虽然根据丹尼尔的回复,我认为他理解我的意思。
    【解决方案4】:

    这还不够。 1. 你缺少 cookie,$_COOKIE 变量。 2. 如果你使用 $_REQUEST 你就有麻烦了。 3.您没有显示您的查询,当您将每个变量放入查询时,您必须用单引号 '' 引用每个变量(特别是当数据被假定为整数并且您可能认为在这种情况下不需要引号时,但这将是一个很大的错误)。 4. 查询中使用的数据可能来自其他来源。

    最好的方法是使用数据绑定,并让驱动自动转义数据,这在 PDO 扩展中可用。

    示例代码:

    $PDO = new PDO('mysql:dbname=testdb;host=127.0.0.1' $user, $password);
    $stmt = $PDO->prepare("SELECT * FROM test WHERE id=? AND cat=?");
    $stmt->execute(array($_GET["id"], $_GET["cat"]));
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
    

    您还可以使用字符串键绑定数据:

    $stmt = $PDO->prepare("SELECT * FROM test WHERE id = :id AND cat = :cat");
    $stmt->execute(array(":id" => $_GET["id"], ":cat" => $_GET["cat"]));
    

    如果你想学习 PDO,你可能会发现我使用的这些辅助函数很有用:

    http://www.gosu.pl/var/PDO.txt

    PDO_Connect(dsn, user, passwd) - connects and sets error handling.
    PDO_Execute(query [, params]) - only execute query, do not fetch any data.
    PDO_InsertId() - last insert id.
    
    PDO_FetchOne(query [, params]) - fetch 1 value, $count = PDO_FetchOne("SELECT COUNT(*) ..");
    PDO_FetchRow(query [, params]) - fetch 1 row.
    PDO_FetchAll(query [, params]) - fetch all rows.
    PDO_FetchAssoc(query [, params]) - returns an associative array, when you need 1 or 2 cols
    
    1) $names = PDO_FetchAssoc("SELECT name FROM table");
    the returned array is: array(name, name, ...)
    
    2) $assoc = PDO_FetchAssoc("SELECT id, name FROM table")
    the returned array is: array(id=> name, id=>name, ...)
    
    3) $assoc = PDO_FetchAssoc("SELECT id, name, other FROM table");
    the returned array is: array(id=> array(id=>'',name=>'',other=>''), id=>array(..), ..)
    

    每个获取数据的函数都接受作为第二个参数参数数组(这是可选的),用于针对 sql 注入的自动数据绑定。本文前面已经介绍了它的用法。

    【讨论】:

    • 不能说这些查询是否安全,因为整个 "$inserts=" 行没有使用 $_GET/$_POST 变量。第 3 行也是如此,使用 '$cid'。
    • 对.. 所有登录和插入都是通过 post 完成的。 Orly 我的一些拉取数据的查询是用 GET 完成的,但我尽量避免这种情况。感谢您抽出宝贵时间..
    • 看来我的下一个研究领域是 PDO……第一次阅读它
    • 我已经编辑了我的答案并添加了一个指向我自己编写的一些 PDO 函数的链接,这些函数使使用 PDO 变得更加容易。
    • 使用 PDO 你可以连接到任何你喜欢的数据库,所以当你学会它后,你将能够对所有数据库使用相同的功能:mysql、postgresql、sqlite - 你只需要改变从“mysql”到“sqlite”的dsn。
    【解决方案5】:

    这是完全错误的方法。

    事实上,您是在模仿臭名昭著的魔术引语,这被认为是一种不好的做法。有所有的缺点和危险。

    【讨论】:

    • 好的,你能指出我正确的方向吗?也许是一个教程。我开始构建广泛的数据管理系统,不想从不良做法开始。感谢您的回复。
    • 虽然准备好的陈述是很好的解决方案,如果您想更好地理解这里有一些链接供您使用
    猜你喜欢
    • 2021-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-25
    • 2013-02-25
    • 1970-01-01
    • 1970-01-01
    • 2015-06-04
    相关资源
    最近更新 更多