如何防止PHP中的SQL注入?

如何防止PHP中的SQL注入?,php,mysql,sql,security,sql-injection,Php,Mysql,Sql,Security,Sql Injection,如果未经修改就将用户输入插入到SQL查询中,则应用程序易受攻击,如以下示例所示: $safe_variable=$_POST['user_input']; mysql_查询(“插入到`table`(`column`)值(`unsafe_variable'); 这是因为用户可以输入类似于value')的内容;升降台--,则查询变为: INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--') 如何防止这种情况发生?

如果未经修改就将用户输入插入到SQL查询中,则应用程序易受攻击,如以下示例所示:

$safe_variable=$_POST['user_input'];
mysql_查询(“插入到`table`(`column`)值(`unsafe_variable');
这是因为用户可以输入类似于
value')的内容;升降台--,则查询变为:

INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')
如何防止这种情况发生?

我建议使用(PHP数据对象)来运行参数化SQL查询

这不仅可以防止SQL注入,还可以加快查询速度

通过使用PDO而不是
mysql
mysqli
pgsql
函数,您可以使应用程序从数据库中更抽象一点,很少需要切换数据库提供程序。

我建议使用(PHP数据对象)来运行参数化SQL查询

这不仅可以防止SQL注入,还可以加快查询速度


通过使用PDO而不是
mysql
mysqli
pgsql
函数,您可以使您的应用程序从数据库中更抽象一点,而很少需要切换数据库提供程序。

您可以执行以下基本操作:

$safe_variable = mysqli_real_escape_string($_POST["user-input"], $dbConnection);
mysqli_query($dbConnection, "INSERT INTO table (column) VALUES ('" . $safe_variable . "')");
"SELECT title FROM article WHERE id = " . mysql_real_escape_string($_GET["id"])
SELECT ... WHERE id = UNHEX('2d312075...3635');

这并不能解决所有问题,但它是一个很好的垫脚石。我省略了一些明显的项目,例如检查变量的存在性、格式(数字、字母等)。

您可以执行以下基本操作:

$safe_variable = mysqli_real_escape_string($_POST["user-input"], $dbConnection);
mysqli_query($dbConnection, "INSERT INTO table (column) VALUES ('" . $safe_variable . "')");
"SELECT title FROM article WHERE id = " . mysql_real_escape_string($_GET["id"])
SELECT ... WHERE id = UNHEX('2d312075...3635');
这并不能解决所有问题,但它是一个很好的垫脚石。我遗漏了一些明显的项目,比如检查变量的存在性、格式(数字、字母等)

不推荐的警告: 这个答案的示例代码(与问题的示例代码一样)使用PHP的
MySQL
扩展,该扩展在PHP5.5.0中被弃用,在PHP7.0.0中被完全删除

安全警告:此答案不符合安全最佳做法,使用事先准备好的语句。使用下面概述的策略,风险自负。(另外,
mysql\u real\u escape\u string()
在PHP7中被删除。)

如果您使用的是最新版本的PHP,下面列出的
mysql\u real\u escape\u string
选项将不再可用(尽管
mysqli::escape\u string
是一个现代等效选项)。如今,
mysql\u real\u escape\u string
选项只适用于旧版本PHP上的遗留代码


您有两种选择—转义
不安全变量中的特殊字符
,或使用参数化查询。两者都可以防止SQL注入。参数化查询被认为是更好的做法,但在使用它之前,需要更改为PHP中较新的MySQL扩展

我们将首先讨论下冲击管柱

//Connect

$unsafe_variable = $_POST["user-input"];
$safe_variable = mysql_real_escape_string($unsafe_variable);

mysql_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')");

//Disconnect
另请参见函数的详细信息

要使用参数化查询,您需要使用而不是函数。为了重写您的示例,我们需要如下内容

<?php
    $mysqli = new mysqli("server", "username", "password", "database_name");

    // TODO - Check that connection was successful.

    $unsafe_variable = $_POST["user-input"];

    $stmt = $mysqli->prepare("INSERT INTO table (column) VALUES (?)");

    // TODO check that $stmt creation succeeded

    // "s" means the database expects a string
    $stmt->bind_param("s", $unsafe_variable);

    $stmt->execute();

    $stmt->close();

    $mysqli->close();
?>

您需要了解的关键功能是

此外,正如其他人所建议的,您可能会发现使用以下内容来提升抽象层很有用/更容易

请注意,您询问的案例相当简单,更复杂的案例可能需要更复杂的方法。特别是:

  • 如果您想根据用户输入改变SQL的结构,参数化查询将不会有帮助,而且所需的转义不在
    mysql\u real\u escape\u string
    中。在这种情况下,最好通过白名单传递用户的输入,以确保只允许“安全”值通过
  • 如果您在条件中使用用户输入的整数,并采用
    mysql\u real\u escape\u string
    方法,您将遇到下面注释中描述的问题。这种情况更为棘手,因为整数不会被引号包围,所以您可以通过验证用户输入只包含数字来处理
  • 可能还有其他我不知道的案例。您可能会发现,在您可能遇到的一些更微妙的问题上,这是一个有用的资源
不推荐的警告: 这个答案的示例代码(与问题的示例代码一样)使用PHP的
MySQL
扩展,该扩展在PHP5.5.0中被弃用,在PHP7.0.0中被完全删除

安全警告:此答案不符合安全最佳做法,使用事先准备好的语句。使用下面概述的策略,风险自负。(另外,
mysql\u real\u escape\u string()
在PHP7中被删除。)

如果您使用的是最新版本的PHP,下面列出的
mysql\u real\u escape\u string
选项将不再可用(尽管
mysqli::escape\u string
是一个现代等效选项)。如今,
mysql\u real\u escape\u string
选项只适用于旧版本PHP上的遗留代码


您有两种选择—转义
不安全变量中的特殊字符
,或使用参数化查询。两者都可以防止SQL注入。参数化查询被认为是更好的做法,但在使用它之前,需要更改为PHP中较新的MySQL扩展

我们将首先讨论下冲击管柱

//Connect

$unsafe_variable = $_POST["user-input"];
$safe_variable = mysql_real_escape_string($unsafe_variable);

mysql_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')");

//Disconnect
另请参见函数的详细信息

要使用参数化查询,您需要使用而不是函数。为了重写您的示例,我们需要如下内容

<?php
    $mysqli = new mysqli("server", "username", "password", "database_name");

    // TODO - Check that connection was successful.

    $unsafe_variable = $_POST["user-input"];

    $stmt = $mysqli->prepare("INSERT INTO table (column) VALUES (?)");

    // TODO check that $stmt creation succeeded

    // "s" means the database expects a string
    $stmt->bind_param("s", $unsafe_variable);

    $stmt->execute();

    $stmt->close();

    $mysqli->close();
?>

您需要了解的关键功能是

此外,正如其他人所建议的,您可能会发现使用以下内容来提升抽象层很有用/更容易

$unsafe_variable = $_POST['user_id'];

$safe_variable = (int)$unsafe_variable ;

mysqli_query($conn, "INSERT INTO table (column) VALUES ('" . $safe_variable . "')");
$query="select * from users where email='".$_POST['email']."' and password='".$_POST['password']."' ";
$_POST['email']= admin@emali.com' OR '1=1
$query="select * from users where email='admin@emali.com' OR '1=1';
SELECT * FROM users WHERE name = '".mysql_escape_string($name_from_html_form)."'
wHERE 1=1   or  LIMIT 1
SELECT * FROM users WHERE name = '".mysql_escape_string($name_from_html_form)."' LIMIT 1
string mysqli_real_escape_string ( mysqli $link , string $escapestr )
$iId = $mysqli->real_escape_string("1 OR 1=1");
$mysqli->query("SELECT * FROM table WHERE id = $iId");
$count = DB::column('SELECT COUNT(*) FROM `user`);
$pairs = DB::pairs('SELECT `id`, `username` FROM `user`);
$user = DB::row('SELECT * FROM `user` WHERE `id` = ?', array($user_id));
$banned_users = DB::fetch('SELECT * FROM `user` WHERE `banned` = ?', array(TRUE));
SELECT password FROM users WHERE name = 'root';
SELECT password FROM users WHERE name = 0x726f6f74;
SELECT password FROM users WHERE name = UNHEX('726f6f74');
"SELECT title FROM article WHERE id = " . mysql_real_escape_string($_GET["id"])
SELECT ... WHERE id = -1 UNION ALL SELECT table_name FROM information_schema.tables;
SELECT ... WHERE id = -1 UNION ALL SELECT column_name FROM information_schema.column WHERE table_name = __0x61727469636c65__;
SELECT ... WHERE id = UNHEX('2d312075...3635');
$request = $pdoConnection->("INSERT INTO parents (name, addr, city) values ($name, $addr, $city)");
$request = $pdoConnection->("INSERT INTO parents (name, addr, city) values (?, ?, ?);
$request = $pdoConnection->("INSERT INTO parents (name, addr, city) value (:name, :addr, :city)");
$request = $mysqliConnection->prepare('
       SELECT * FROM trainers
       WHERE name = ?
       AND email = ?
       AND last_login > ?');

    $query->bind_param('first_param', 'second_param', $mail, time() - 3600);
    $query->execute();
 GRANT SELECT, INSERT, DELETE ON database TO username@'localhost' IDENTIFIED BY 'password';
FLUSH PRIVILEGES; 
select * from mysql.user where User='username';
[1] UNION SELECT IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0) User,Password FROM mysql.user WHERE User = 'root'
$user = "''1''"; // Malicious keyword
$sql = 'SELECT * FROM awa_user WHERE userame =:username';
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':username' => $user));
    189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\''
    189 Quit
$stmt = $mysqli->prepare("SELECT * FROM awa_user WHERE username =?")) {
$stmt->bind_param("s", $user);
$user = "''1''";
$stmt->execute();
    188 Prepare   SELECT * FROM awa_user WHERE username =?
    188 Execute   SELECT * FROM awa_user WHERE username ='\'\'1\'\''
    188 Quit
RewriteCond %{QUERY_STRING} ([0-9]+)=([0-9]+)
RewriteRule ^(.*) ^/track.php
$mysqli = new mysqli('host', 'user', 'password', 'database');
$mysqli->set_charset('charset');

$string = $mysqli->real_escape_string($string);
$mysqli->query("INSERT INTO table (column) VALUES ('$string')");
$stmt = $mysqli->prepare("INSERT INTO table (column1, column2) VALUES (?,?)");

$stmt->bind_param("is", $integer, $string);

$stmt->execute();
$string = "x' OR name LIKE '%John%";
$integer = '5 OR id != 0';

$query = sprintf( "SELECT id, email, pass, name FROM members WHERE email ='%s' AND id = %d", $mysqli->real_escape_string($string), $integer);

echo $query;
// SELECT id, email, pass, name FROM members WHERE email ='x\' OR name LIKE \'%John%' AND id = 5

$integer = '99999999999999999999';
$query = sprintf("SELECT id, email, pass, name FROM members WHERE email ='%s' AND id = %d", $mysqli->real_escape_string($string), $integer);

echo $query;
// SELECT id, email, pass, name FROM members WHERE email ='x\' OR name LIKE \'%John%' AND id = 2147483647
$unsafe_variable = mysql_real_escape_string($_POST['user_input']);
$unsafe_variable = (is_string($_POST['user_input']) ? $_POST['user_input'] : '');
$unsafe_variable = (is_numeric($_POST['user_input']) ? $_POST['user_input'] : '');
$conn = oci_connect($username, $password, $connection_string);
$stmt = oci_parse($conn, 'UPDATE table SET field = :xx WHERE ID = 123');
oci_bind_by_name($stmt, ':xx', $fieldval);
oci_execute($stmt);
function sqlvprintf($query, $args)
{
    global $DB_LINK;
    $ctr = 0;
    ensureConnection(); // Connect to database if not connected already.
    $values = array();
    foreach ($args as $value)
    {
        if (is_string($value))
        {
            $value = "'" . mysqli_real_escape_string($DB_LINK, $value) . "'";
        }
        else if (is_null($value))
        {
            $value = 'NULL';
        }
        else if (!is_int($value) && !is_float($value))
        {
            die('Only numeric, string, array and NULL arguments allowed in a query. Argument '.($ctr+1).' is not a basic type, it\'s type is '. gettype($value). '.');
        }
        $values[] = $value;
        $ctr++;
    }
    $query = preg_replace_callback(
        '/{(\\d+)}/', 
        function($match) use ($values)
        {
            if (isset($values[$match[1]]))
            {
                return $values[$match[1]];
            }
            else
            {
                return $match[0];
            }
        },
        $query
    );
    return $query;
}

function runEscapedQuery($preparedQuery /*, ...*/)
{
    $params = array_slice(func_get_args(), 1);
    $results = runQuery(sqlvprintf($preparedQuery, $params)); // Run query and fetch results.   
    return $results;
}
runEscapedQuery("INSERT INTO Whatever (id, foo, bar) VALUES ({0}, {1}, {2})", $numericVar, $stringVar1, $stringVar2);
$user = ORM::for_table('user')
->where_equal('username', 'j4mie')
->find_one();

$user->first_name = 'Jamie';
$user->save();

$tweets = ORM::for_table('tweet')
    ->select('tweet.*')
    ->join('user', array(
        'user.id', '=', 'tweet.user_id'
    ))
    ->where_equal('user.username', 'j4mie')
    ->find_many();

foreach ($tweets as $tweet) {
    echo $tweet->text;
}