我知道这个问题已经被问了一百万次,但是今天(2013 年)在 SQL 语句中运行变量之前验证查询字符串的标准是什么?
例如,如果我通过 $_GET['id'] 从 url 接收到变量“id”:
$id = $_GET['id'];
...运行前我应该做什么:
SELECT * FROM users WHERE id="$id"
这够了吗:
$id = mysql_real_escape_string($_GET['id']);
...对于这个具体的例子?
我知道这个问题已经被问了一百万次,但是今天(2013 年)在 SQL 语句中运行变量之前验证查询字符串的标准是什么?
例如,如果我通过 $_GET['id'] 从 url 接收到变量“id”:
$id = $_GET['id'];
...运行前我应该做什么:
SELECT * FROM users WHERE id="$id"
这够了吗:
$id = mysql_real_escape_string($_GET['id']);
...对于这个具体的例子?
这无关紧要,因为在大多数常规情况下 id 都是整数。你必须使用:
$id = (int)$_GET['id'];
现在的标准方法是使用参数化查询/准备语句,这些语句在 MySQLi 和 PDO 的库中表示。
对于任何手动验证,您需要明智地考虑您希望收到此变量的内容。
在这种情况下,您只需要整数,没有别的。你不需要人们通过 ID -> 发送1 UNION SELECT ...
它仍然是一个有效的字符串,并且 mysql_real_escape_string 不会对它做任何事情。
在这种情况下,最简单的验证就是强制转换为整数。
<?php
$id = (int) $_GET['id'];
$sql = "SELECT * FROM users WHERE id=$id";
然后,您不需要在 SQL 表达式中的变量周围加上引号。事实上,在某些情况下,在数字文字周围使用引号会扰乱 SQL 优化器,所以我总是很困惑为什么这么多人养成这种习惯。
如果您想进行更复杂的验证,请阅读PHP 的过滤器扩展。
最后,在 SQL 中使用变量的更好(更简单、更快、更安全)的方法是使用查询参数。但是 PHP 的弃用mysql_*
函数不支持查询参数,所以你应该学习mysqli或PDO。
您可能应该mysqli
从 deprecated切换到mysql_
可以利用mysql::prepare()
它允许您使用占位符的位置:
$stmt = $mysqli->prepare("SELECT District FROM City WHERE Name=?");
$stmt->bind_param("s", $city);
$stmt->execute();
SQL 所能获得的安全性。
但是mysql_real_escape_string()
足以防止 SQL 注入(只要将字符串括在引号中)。