首页 > 解决方案 > 使用 preg_match 时是否需要转义字符串?

问题描述

我正在使用一个简单的 HTML Web 表单来收集用户名和密码。我preg_match过去只允许 AZ,0-9 个字符用于用户名。我正在使用以下代码:

if (preg_match('/[^A-Za-z0-9]/', $_POST["username"]))  {
    echo '<script>alert("Usernames can only contain A-Z, 0-9")</script>';
}

我是否需要使用mysqli_real_escape_string才能转义此字符串?如果是这样,它是否仍然适用于所有情况?如果不是,我将面临哪些安全风险,我该如何预防?

(我在将用户名放入我的查询和数据库之前对其进行转义)

标签: phpmysqlmysqli

解决方案


你永远不应该使用mysqli_real_escape_string. 只是忘记这个功能甚至存在。

如果您将 PHP 变量放在 SQL 中,那么即使您对它们进行转义,您也没有正确执行此操作。您必须使用参数绑定并且不要以任何方式修改输入,除非您的业务逻辑需要它。

为了防止 SQL 注入(我认为这是您的目标),您必须使用占位符和参数绑定。在 mysqli 中,它看起来像这样:

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli('localhost', 'user', 'pass', 'db');
$mysqli->set_charset('utf8mb4'); // always set the charset

$username = $_POST["username"];
$password = password_hash($_POST["password"], PASSWORD_DEFAULT);

$stmt = $mysqli->prepare('INSERT INTO users(username, passwordHash) VALUES(?,?)');
$stmt->bind_param('ss', $username, $password);
$stmt->execute();

我建议从 mysqli 切换到 PDO。它提供更多并且更易于使用。在 PDO 中,相同的示例如下所示:

$dsn = "mysql:host=localhost;dbname=db;charset=utf8mb4";
$pdo = new PDO($dsn, $user, $pass, [
    \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
    \PDO::ATTR_EMULATE_PREPARES => false
]);

$username = $_POST["username"];
$password = password_hash($_POST["password"], PASSWORD_DEFAULT);

$stmt = $pdo->prepare('INSERT INTO users(username, passwordHash) VALUES(?,?)');
$stmt->execute([$username, $password]);

推荐阅读