【问题标题】:Is this PHP code vulnerable to SQL injection? [duplicate]这个 PHP 代码是否容易受到 SQL 注入的影响? [复制]
【发布时间】:2012-04-28 17:31:03
【问题描述】:

我有一个网站,我在服务器端使用 PHP 并使用 mysql 作为数据库。我使用以下脚本从数据库中检索数据。谁能让我知道这段代码是否容易受到注入攻击?如果可以,请给个解决方案?

<?php
// PHP script 

$usrname=$_POST['usrname'];
$_SESSION['usremail']=$usrname;
$usrpassword=$_POST['passwd']; 
$db=mysql_select_db('mydb',$connection);
$result=mysql_query("select usrfname,usrlname from userinformation where usremail='$usrname' and usrpassword='$usrpassword'") or die('failed to login');

非常感谢任何帮助。

谢谢

【问题讨论】:

  • 这是测验题吗? $usrname 的值从何而来?如果有的话,它是如何“保护”的?
  • 是的,这很容易被注入。此外,您似乎正在以明文形式存储密码;不是一个好主意。
  • 当您对问题投反对票时,请给出理由。这是一个非常好的问题,绝对不会“过于本地化”。
  • @pst: 在$_POST 它必须来自一个表单,我看不出有任何(认真)保护它的方法。
  • @nico 因此引用。此外,“保护”有多种类型,唯一适用于 SQL-Injection 的一种是确保语句结构不会被更改的那种;但是,可能还有其他非 SQL 注入使用问题。 (占位符是这个问题的通用解决方案。)

标签: php mysql


【解决方案1】:

是的,它很脆弱。您直接从用户输入中谈论值并将其放入您的查询中。

您应该查看mysql_real_escape_string,或者(最好)使用提供参数化查询的 MySQLi。 SQL 注入是由作为 SQL 代码而不是数据注入的用户数据引起的。确保查询安全的唯一真正方法是使用参数化查询,它在协议级别分离数据和查询文本。

此外,您的密码以明文形式存储。您应该使用盐渍哈希函数作为绝对最小值。

您还应该看看这些真棒问题:

【讨论】:

  • +1 表示“使用 ... 参数化查询”
【解决方案2】:

当然它很脆弱。你永远不会清理你的输入。尽管不推荐使用 mysql_* 函数,但您仍然会发现使用 mysql_real_escape_string 函数。只需将其应用于您的变量即可。

$usrname = mysql_real_escape_string($_POST['usrname']);
$usrpassword = mysql_real_escape_string($_POST['passwd']);

【讨论】:

  • 或者像现在这样使用参数化查询。
  • 部分 mysql_ 函数已被弃用,但并非全部。
  • 当然,使用 PDO 或 MySQLi 会是更好的解决方案。
  • 请记住,mysql_real_escape_string万无一失的。它只是对必须转义的字符执行黑名单过滤。它不会将数据与查询语言分开。因此,我可以通过 1=1 并让它完全搞砸您的查询逻辑。如果你想对 SQL 注入有真正的安全性,我真的希望你这样做,你必须使用一种将查询语言与输入数据完全分开的机制——MySQLi 和 PDO 中的参数化查询可以做到这一点。
  • @Polynomial:你能举个例子说明你如何传递 1=1 吗? mysql_real_escape_string 删除了所有单引号,因此您的 1=1 在查询中始终是 '1=1',只是一个字符串,不是吗?
【解决方案3】:

是的,它是..

改为这样做:

$usrname=$_POST['usrname'];
$_SESSION['usremail']=$usrname;
$usrname=mysql_real_escape_string($usrname);
$usrpassword=mysql_real_escape_string($_POST['passwd']); 
$db=mysql_select_db('mydb',$connection);
$result=mysql_query("select usrfname,usrlname from userinformation where usremail='$usrname' and usrpassword='$usrpassword'") or die('failed to login');`

您还应该查看Prepared Statements。

【讨论】:

  • 正如我在其他答案中所述,不要使用旧的不推荐使用的功能。如果您想要任何表面上的安全性,准备好的语句是唯一的方法。
【解决方案4】:

在您想在查询中使用的用户生成字符串上使用mysql_real_escape_string()

$usrname     = mysql_real_escape_string($_POST['usrname']);
$usrpassword = mysql_real_escape_string($_POST['passwd']); 

$db=mysql_select_db('mydb',$connection);
$result = mysql_query("SELECT usrfname, usrlname FROM userinformation WHERE usremail='$usrname' AND usrpassword='$usrpassword'") or die('failed to login');

// Set session data only if login is successful 
$_SESSION['usremail']=$usrname;

【讨论】:

  • 请不要提倡使用已弃用的函数。准备好的语句是针对 SQL 注入攻击提供可靠安全性的唯一方法。
  • mysql_real_escape_string() 不是一个已弃用的函数,虽然准备好的语句让生活更轻松,但它不是提供针对 SQL 注入的安全性的唯一方法,它只允许您编写有点草率的代码。 ;)
  • php.net/manual/en/pdo.prepared-statements.php 是开始研究“准备好的陈述”的一个地方 阅读 30 秒后,您就会明白为什么这会给您带来安全性的巨大飞跃。
  • @fhugas 但是mysql_query 已被弃用,PHP 开发人员建议不要使用旧式程序查询函数。 mysql_real_escape_string 函数对 SQL 注入也不是 100% 有效。例如,如果您使用"SELECT * FROM users WHERE id = " . mysql_real_escape_string($_GET['id']),我可以将1=1 注入ID 字段并让查询返回所有值。潜在的安全问题就在那里:)
  • 呵呵,但它仍然没有被弃用;)看起来你忘了在你的查询中引用那个输入 `"SELECT * FROM users WHERE id = '" 。 mysql_real_escape_string($_GET['id']) ."'";现在你不能注入任何东西.. :)
【解决方案5】:

是的,您不应该接受用户输入(来自表单(POST 数据)、作为 url 的一部分(GET 数据)甚至是 cookie,而不首先检查它是您所期望的。例如,您的用户名可能包含从 a 到 z 可能允许使用一个点。因此,在将输入文本放在数据库附近之前,您会检查它所包含的全部内容。Google preg_match。

而且你需要在服务器端做,仅仅在浏览器上使用javascript是不够的。

我还将密码存储为用户在注册时输入的 md5 哈希值,因此您在注册时获得 $password,检查其字符范围有限,执行 $hass_pw=md5($password)并将 $hash_pw 存储在 d/b 中。然后,当用户登录时,您再次对其进行哈希处理并在查询中使用它。 (为了清楚起见,我在这里省略了 $_POST)。

例如:

if preg_match(/"[^a-z]/i", $_POST['usrname'])
    print "bad username format)
else    
    {
    // good format username, safe to use in query
    }

【讨论】:

  • 这讨论了如何清理输入(这只是一个副作用,即 特定 匹配是可以有效防止 SQL 注入攻击的字符子集)。但是,它没有谈论 SQL 注入。 SQL 注入是一个特定的漏洞,可以更改 SQL 查询的 结构。可能还有其他漏洞和/或违反业务规则的方式需要解决,这就是这个答案所涵盖的内容。
  • MD5 存储密码?不,这在很长一段时间内都是不安全的,即使考虑到发布日期也是如此。
  • 你真的不应该使用MD5 password hashes,你真的应该使用PHP的built-in functions来处理密码安全。确保你 don't escape passwords 或在散列之前对它们使用任何其他清理机制。这样做会更改密码并导致不必要的额外编码。
猜你喜欢
  • 2012-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-17
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
  • 2020-03-02
相关资源
最近更新 更多