sql注入是web应用程序最容易发生最危险的漏洞之一。成功利用sql注入漏洞可能会导致数据泄露,从而暴露用户名、密码、电子邮件地址、信用卡信息和其他敏感数据。甚至还可能导致整个服务器的损害。
在下面的实例中,article参数被不安全的传递给查询条件:
不安全的代码示例1
2$articleid = $_GET['article'];
$query = "SELECT * FROM articles WHERE articleid = '$articleid'"
如果用户传的article的值为1'+union+select+1,version(),3'
查询就变成了
1$query = "SELECT * FROM articles WHERE articleid = '1'+union+select+1,version(),3''"
显而易见,如果articles只有3个字段的话,就暴露了mysql版本信息。
如果articles不是3个字段的话 就会报错。
现在,更多的攻击者可以枚举数据库的所有表/列 泄露敏感信息。
此问题的解决方案是使用参数化的sql查询(也就是预处理语句)。通过参数化查询,我们基本上通过以两个单独的请求发送数据来让数据库知道哪个部分是查询以及哪个是数据(用户输入),从而消除了混合用户输入和sql查询的可能性。
正如下面的例子所看到的,参数user_id不是直接传递给查询,而是占位符来替换。当我们运行execute()函数时,后端数据库将知道如果替换占位符。
安全代码示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41// We first check if the request meets the specified criteria. To proceed, the user_id variable must not be empty, be numeric and less than 5 characters long.
if((!empty($_GET['user_id'])) && (is_numeric($_GET['user_id'])) && (mb_strlen($_GET['user_id'])<5)) {
// If the request is valid we proceed
$servername = "localhost";
$username = "username";
$password = "password";
$database = "dbname";
// Establish a new connection to the SQL server using PDO
try {
$conn = new PDO("mysql:host=$servername;dbname=$database", $username, $password);
// Assign user input to $user_id variable
$user_id = $_GET['user_id'];
// Prepare the query and set a placeholder for user_id
$sth = $conn->prepare('SELECT user_name, user_surname FROM users WHERE user_id=?');
// Execute the query by providing the user_id parameter in an array
$sth->execute(array($user_id));
// Fetch all matching rows
$user = $sth->fetch();
// If there is a matching user, display their info
if(!empty($user)) {
echo "Welcome ".$user['user_name']." ".$user['user_surname'];
} else {
echo "No user found";
}
// Close the connection
$dbh = null;
} catch(PDOException $e) {
echo "Connection failed.";
}
} else {
echo "User ID not specified or invalid.";
}
使用上述方法,我们可以安全地从数据库中选择数据。
避免使用mysql(i)_extensions,一定要用PDO来写sql.
Mysql(已启用)和Mysqli扩展已过时,但仍然可以使用。建议用PDO(php数据对象)替代。PDO不仅是面向对象的,而且支付预处理语句,并且它允许你在需要时移动到另一个sql数据库服务器,只需对代码稍作修改。