本章将学习如何避免常见的数据库漏洞。
什么是SQL注入?
SQL注入是一种攻击,当web服务器从浏览器接受用户输入时,如果web应用程序有漏洞,攻击者有可能注入恶意SQL代码。
SQL注入攻击可能引起敏感信息暴露,如用户的联系电话、电子邮件地址、信用卡信息等。利用它,攻击者甚至能绕过身份验证,访问整个数据库。
SQL注入的工作原理
考虑下面的SQL语句,当web应用程序中的用户登录时,验证用户名和密码。
SELECT * FROM users WHERE username='username_val' AND password='password_val';
这里,username_val
和password_val
分别表示用户输入的用户名和密码。如果用户输入“john”作为用户名,“123”作为密码,那么结果语句将是:
SELECT * FROM users WHERE username='john' AND password='123';
但是假设用户是攻击者,输入了类似于' OR 'x'='x
的值
在这种情况下,上面的SQL查询将被构造为:
SELECT * FROM users WHERE username='' OR 'x'='x' AND password='' OR 'x'='x';
这个语句是一个有效的SQL语句,因为'x'='x'
总是成立,所以查询将返回users表中的所有行。可以看到攻击者使用一个小技巧,就可以轻松地访问数据库的所有敏感信息。
如果users表非常大,包含数百万行数据,这条语句还可能导致拒绝服务攻击(DDoS攻击),方法是消耗系统资源,使你的应用程序不能正常提供服务。
防止SQL注入
始终验证用户输入。永远不要直接使用用户输入的内容来构建SQL语句。如果使用PHP和MySQL,可以使用mysqli_real_escape_string()
函数创建一个合法的SQL字符串。
下面是一个使用PHP和MySQL进行用户身份验证的简单示例,演示了如何在获取用户输入的同时防止SQL注入。
<?php
// Starting session
session_start();
/* Attempt MySQL server connection. Assuming you are running MySQL
server with default setting (user 'root' with no password) */
$link = mysqli_connect("localhost", "root", "", "demo");
// Check connection
if($link === false){
die("ERROR: Could not connect to database.");
}
// Escape user inputs for security
$username_val = mysqli_real_escape_string($link, $_POST['username']);
$password_val = mysqli_real_escape_string($link, $_POST['password']);
if(isset($username_val, $password_val)){
// Attempt select query execution
$sql = "SELECT * FROM users WHERE username='" . $username_val . "' AND password='" . $password_val . "'";
if($result = mysqli_query($link, $sql)){
if(mysqli_num_rows($result) == 1){
// User is authenticated do your stuff here
$row = mysqli_fetch_array($result);
/* Holding values in session variable so that it can be
accessed later within the same session reference */
$_SESSION['user_id'] = $row['user_id'];
$_SESSION['first_name'] = $row['first_name'];
header('Location: welcome.php');
} else{
echo "ERROR: Invalid username or password.";
}
} else{
echo "ERROR: Something went wrong. Please try again.";
}
}
// Close connection
mysqli_close($link);
?>