选择查询的准备语句问题

Posted

技术标签:

【中文标题】选择查询的准备语句问题【英文标题】:Problems with prepared statements for a select query 【发布时间】:2018-10-21 22:23:35 【问题描述】:

我有一个在 php/mysql 上运行的应用程序,它最近进入了生产阶段,所以我需要保护整个基础设施,从一些防止 SQL 注入的保护开始。 我正在做的一件事是将用户的所有输入转换为准备好的语句而不是直接查询。 在我开始在登录页面上工作之前,这非常有效。 以下代码为(仅限mysql查询)

    我今天使用的(不安全的)但功能正常的代码 替换它的代码不起作用。

对于这个例子,user_list 将是我数据库上的表和usr,pswHash 检查登录的字段。 id 将是自动递增的行标识符。

1)

$sql_query = "SELECT * FROM user_list WHERE usr = $user AND pswHash = $passHash";

2)

$stmt = $mysqli->prepare("SELECT * FROM user_list WHERE usr=? AND pswHash=?");
$stmt->bind_param('ss', $user, $passHash);

第二个代码片段不起作用,因为无论使用正确还是错误的 usr/pass 组合,查询的输出在任何情况下都将为空。

如果这还不够,我可以发布整个 sn-ps,但我猜这个问题与 SQL 查询有关。 谢谢你的帮助

【问题讨论】:

对我来说看起来不错。你检查过mysqli errors吗? 旁注:您如何对密码进行哈希处理?你应该使用password_hash()password_verify() 你缺少$stmt->execute();$stmt->fetch(); 顺便说一句,这不是在 PHP 中使用密码的正确方法,即使密码是由外部程序管理的(例如:Active Directory) '它最近进入了生产阶段' - 所以现在你想让它安全吗?! 【参考方案1】:

下面是我的编码方式:

function password_matches($mysqli, $user, $pass) 
    $stmt = $mysqli->prepare("SELECT pswHash FROM user_list WHERE usr=?");
    // always check for errors after prepare()
    if (!$stmt) 
      error_log($mysqli->error);
      return false;
    
    $stmt->bind_param('s', $user);

    $ok = $stmt->execute();
    // always check for errors after execute()
    if (!$ok) 
      error_log($mysqli->error);
      return false;
    

    $result = $stmt->get_result();
    while ($row = $result->fetch_assoc()) 
      if (password_verify($pass, $row['pswHash'])) 
        return true;
      
    
    // if the result set had zero matches for $user,
    // or if there were any matches for $user, but none of them
    // had a password hash matching the input
    return false;

这是假设您在将密码哈希插入数据库之前使用password_hash() 创建密码哈希。

始终检查prepare()execute() 以查看它是否返回false。如果有,请记录$mysqli->error,并继续关注您的 http 服务器错误日志。这是开发 SQL 查询时的一般建议。如果您编写了错误的 SQL 语法,或者您没有正确的 SQL 权限,或者发生了其他事情,您想知道。

【讨论】:

以上是关于选择查询的准备语句问题的主要内容,如果未能解决你的问题,请参考以下文章

什么时候在 PHP Mysqli 中使用准备好的语句? - 用户表单搜索输入与选择查询

如果我使用一个语句选择属性然后使用多个 sql 查询的 1 个准备好的语句,我是不是需要使用连接池

限制准备好的语句一次执行一个查询

准备好的语句中的占位符

如何使用准备好的语句选择 IP 地址

从准备好的语句中获取数据