【问题标题】:Best Way to Secure SQL Query in PHP在 PHP 中保护 SQL 查询的最佳方法
【发布时间】:2011-08-15 06:24:31
【问题描述】:

如果我使用 PHP 在 MySQL 数据库上运行查询,如下所示:

$query="SELECT * FROM tablename";

从 SQL 注入之类的事情中保护它的最佳方法是什么?我听说过一些转义方法,但它不会在查询中留下斜杠吗?

【问题讨论】:

  • 根据定义,此特定查询不受 sql 注入影响
  • “切换到PDO并使用准备好的语句而不是将字符串粘贴在一起”是一个有效的答案吗?
  • 只有在有WHERE 子句时才会发生SQL 注入假设您的查询是SELECT * FROM tablename WHERE id='$_POST['id']' 假设我在id 的表单字段中输入' OR '1'='1。您的 sql 查询现在将变为 SELECT * FROM tablename WHERE id='' OR '1' = '1',它将始终返回所有字段。

标签: php mysql sql


【解决方案1】:

您在问题中显示的查询不使用用户提供的值,因此没有 SQL 注入的情况,但在一般情况下:-

首先,在查询中使用之前,您必须验证所有用户输入(用户名、电子邮件等)。例如:- 如果您在用户名中只允许使用字母数字字符,那么您必须在继续形成数据库查询之前检查输入是否实际上是字母数字,并且您还必须检查所有输入的大小。

之后,在我看来,Prepared Statements 是防止 SQL 注入的最佳选择。

mysql_real_escape_string() 的问题:-

由于 mysql_real_escape_string() 根据默认字符集转义字符,因此它比 addlashes() 函数更好,并且可以正确清理 SQL injections arising out of abuse of multibyte character sets,但在另一篇文章 here 中,显示了一个解决方法场景,解释了注入可以还是要完成。

解决方案:-

所以防止 SQL 注入的正确和更好的方法是使用准备好的语句。这是一种在插入用户输入(参数)之前预编译 SQL 语句并将其视为可重用 SQL 模板的技术。因此,它将用户输入与实际的 SQL 代码分开,并且 SQL 解析器从不解析用户输入。

除了安全性之外,它还优化了 SQL 查询的速度。当您需要使用不同的用户输入多次运行相同的查询时,它会有所帮助。

实现细节可以参考PHP手册。

【讨论】:

  • 当我问这个问题时,我对 SQL 的经验要少得多。现在我已经学到了很多,我知道你的答案是最好的答案。我不知道为什么它的分数这么低,但它非常正确。另外,现在不推荐使用 PHP 中的 mysql_* 扩展。不仅如此,在我使用过的任何其他语言中使用 SQL 时,预处理语句似乎是最好的解决方案。
  • 是的,我也对没有任何口头反对的反对票感到惊讶。无论如何,谢谢!
  • @zixtor,他没有具体说明他使用的是什么数据库。并非每次都可以使用准备好的语句。此 Mssql API php.net/manual/en/book.mssql.php 没有任何准备好的语句。这个时候该怎么办?
【解决方案2】:

您不应该选择 * 并且应该只获取您需要的字段。

您需要对用户真正可以输入的文本或使用从中派生的数据进行转义。

您需要使用mysql_real_escape_string()

【讨论】:

  • 那么,如果传递的查询始终是不变的,用户永远无法修改,这是否意味着它是安全的?
  • 并且您确定没有字段可以被篡改,那么是的,我想是的!
  • 兄弟,如果你使用mysql_real_escape_string(),也可以进行SQL注入。
【解决方案3】:

第一个建议,永远不要选择*,只选择必要的字段,如果都需要,则单独选择,这样当其他开发人员继续进行项目时,他们会更快地知道发生了什么。其次,要确保查询安全,请使用mysql_real_escape_string(); 函数,如果正在传递 HTML,请使用 htmlentities(); 函数

【讨论】:

  • “他们会更快地知道发生了什么” --- 如果有 40 个字段,那么读取所有字段不会很快;-)
  • 请问我将如何编写它以选择特定列“column1,column2,column3”?我试过简单的逗号,但它返回错误:S
  • SELECT column1,column2,column3 FROM table WHERE column_name=''
【解决方案4】:

当你做这样的事情时,可以完成 SQL 注入

$query="SELECT * FROM tablename WHERE Name LIKE '" . $_GET["name"] . "'";

攻击者可以简单地将 SQL Injection 放在获取参数名称中 - 例如“' OR 1 OR '' = '”

确保每个 get 或 post 参数都通过 mysql_real_escape_string 或至少 addlashes + intval 传递。

$query="SELECT * FROM tablename WHERE Name LIKE '" . mysql_real_escape_string( $_GET["name"] ) . "'";

【讨论】:

    【解决方案5】:

    根据您的查询,我发现不存在安全问题。
    但是,假设您想在查询中包含一个 GET 参数。

    陈旧的方式

    $query="SELECT * FROM tablename WHERE id = ".$_GET['id'] 
    

    在这里,您有可能有人会更改查询。
    所以你可以做的是使用 mysql_real_escape_string
    正确的方式

     $query="SELECT * FROM tablename WHERE id = '".mysql_real_escape_string($_GET['id'])."'";
    

    这样你就保护了用户发送的参数。

    但是 您应该始终验证来自用户的每个参数,除此之外,您还应通过上面所示的常用方式保护它

    【讨论】:

    • 非常感谢,很高兴知道这一点,非常有帮助!
    【解决方案6】:

    我已经使用了这个代码,请看看它是正确的代码,现在不能注入

    据我所知:如果我们运行插入查询,可以注入注入代码吗? 请纠正我,我不是受过多少教育的程序员

    $rs=mysql_query("Select * from subcat where CATID='".mysql_real_escape_string($_GET['cat'])."' order by ID ASC");
    while($row=mysql_fetch_array($rs))
        {
    
        echo '<td align="left" style="text-decoration:none;padding-left:1px;    "><a href="detail.php?product='.$row['SUBCAT'].'" style="text-decoration:none;color:#000">'.$row['HEADING'].'</a>';
        echo '<td align="CENTER" style="text-decoration:none;padding-left:1px"><a href="detail.php?product='.$row['SUBCAT'].'" style="text-decoration:none;color:#000;">BUY NOW</a>';
        echo '<td align="CENTER" style="text-decoration:none;padding-left:50px"><a href="detail.php?product='.$row['SUBCAT'].'" style="text-decoration:none;font-weight:bold;color:#000">Rs.'.$row['PRICE'].'</a>';
        echo '<tr><td colspan=5 style="border-bottom:1px #232323 solid;">';
        }
    

    【讨论】:

    • 这是一个答案,还是一个问题?问题不属于答案部分。此外,mysql_ 已被弃用。 mysqli_ 或 PDO 应改为使用。
    猜你喜欢
    • 1970-01-01
    • 2021-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-01
    • 2016-11-17
    • 1970-01-01
    相关资源
    最近更新 更多