5

我正在自动化我编写的软件的部署,并且需要能够为新帐户生成新的 mysql 数据库。但是,在清理输入时,我感到担忧。

我正在使用 PDO;但是,显然您不能将准备好的语句与“CREATE DATABASE”一起使用。所以,我也尝试使用 PDO::quote; 但是,然后我新创建的数据库名称用单引号括起来(不是世界末日,但我仍然想避免这种情况)。

有没有办法让它与准备好的语句一起工作?如果没有,我该怎么做才能尽可能保护自己免受 sql 注入攻击?我唯一的另一个想法是允许一个小的字符白名单。

谢谢!

4

1 回答 1

2

您需要编写一个存储过程,然后您可以将经过清理的输入传递给该过程(使用我的示例,您需要更改一些变量,例如数据库名称和正确的用户并传递等,以使其在您的当然是数据库)

例子:

<?php
$dsn = 'mysql:dbname=scratch;host=127.0.0.1';
$user = 'root';
$password = '';

try {
    $dbh = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
    echo 'Connection failed: ' . $e->getMessage();
}

$dbname = 'brand_new_db';

$statement = $dbh->prepare("CALL dbcreator(:db)");
$statement->bindParam(':db',$dbname);

if(!$statement->execute()){
    print_r($statement->errorInfo());
}
else {
    foreach( $dbh->query('SHOW DATABASES')->fetchAll() as $row){
        print "$row[0]" . PHP_EOL;
    }
}

存储过程:

DELIMITER $$

DROP PROCEDURE IF EXISTS `scratch`.`dbcreator` $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `dbcreator`(IN dbname VARCHAR(64))
BEGIN

SET @db = dbname;
SET @statement = CONCAT('CREATE DATABASE ',@db);
PREPARE prepared_statement FROM @statement;
EXECUTE prepared_statement;

END $$

DELIMITER ;

您为PREPARE创建一个 SQL 语句,在我们的例子中,CREATE DATABASE <our database>;因为该CREATE DATABASE语句不适用于变量,然后您只需执行它。最后,您CALL dbcreator('<dbname>')执行存储过程。就是这样CALL dbcreator(:dbname),您可以使用并将参数绑定到。

如您所见,这样您仍然可以在创建数据库时通过 pdo 安全地绑定您的参数。不过,为您创建的所有数据库添加一些固定的短字符串前缀可能不是一个坏主意,以便于查找和区分。在存储过程中,dbname限制为 64 个字符,因为这是 mysql 的当前限制

于 2012-06-17T00:23:48.413 回答