首页 > 解决方案 > mysqli_real_escape_string 是否可以进行 SQL 注入?

问题描述

有没有办法利用此代码并以某个特定的用户名(如 Sam)登录?mysqli_real_escape_string() 函数转义所有 NUL (ASCII 0)、\n、\r、\、'、" 和 Control-Z 字符。

我试过了username = "Sam"domain = "' union (SELECT 1, 123456) # a"但它不起作用..

$user   = $_POST['user'];
$domain = $_POST['domain'];
$pwd    = $_POST['pwd'];

function login($username, $domain, $password) {
    global $vuln_db;
    $starttime = microtime(true);
    $username = mysqli_real_escape_string($vuln_db, trim($username));
    $domain   = mysqli_real_escape_string($vuln_db, trim($domain));
    $password = trim($password);
    if (empty($password) || empty($username) || empty($domain)) {
        return FALSE;
    }
    // We store the password in plaintext to keep the homework's code short.
    // For anything even remotely real, use a proper password storage scheme.
    $query = "SELECT user_id, password FROM users WHERE username = '$username' AND domain LIKE '$domain'";
    $result = mysqli_query($vuln_db, $query) or die(mysqli_error($vuln_db));
    if($result) {
        $row = mysqli_fetch_row($result);
        if($row) {
            $the_password = trim($row[1]);
            for($i = 0; $i < strlen($the_password); $i++) {
                /* Bruteforce is not the way! */
                usleep(100000);
                if($password[$i] != $the_password[$i]) {
                    $endtime = microtime(true);
                    return FALSE;
                }
            }
            return TRUE;
        } else {
            return FALSE;
        }
    }
}

我可以通过 SQL 注入或其他类型的技术从这个函数中得到真实的结果吗?

标签: phpmysqlisql-injection

解决方案


您展示的特定案例是安全的mysqli_real_escape_string()。除非您的字符集是gbksjis,否则我无法分辨,因为我不知道您是如何连接到数据库的。

转义有许多不起作用的边缘情况,如解决 mysql_real_escape_string() 的 SQL 注入的答案中所述。需要仔细考虑和测试,以确保您没有实现在这些边缘情况之一中易受攻击的代码。这种思考和测试使得编写代码需要更长的时间。

这就是为什么当前的最佳实践是使用查询参数而不是转义字符串。

$query = "SELECT user_id, password FROM users WHERE username = ? AND domain LIKE ?";
$stmt = mysqli_prepare($vuln_db, $query) or die(mysqli_error($vuln_db));
$stmt->bind_param('ss', $username, $domain);
$stmt->execute() or die(mysqli_error($vuln_db));
$result = $stmt->get_result() or die(mysqli_error($vuln_db));
  • 查询参数使代码更容易编写,代码更容易阅读
  • 查询参数没有字符串转义的漏洞边缘情况

PS:这与您关于转义的问题无关,但您还应该学习使用password_hash()password_verify(),而不是以纯文本形式存储密码。


推荐阅读