[MYSQL] MySQL防止SQL注入(SQL Injection)实例及措施
发表于:
阅读量:24731
摘要
SQL Injection攻击具有很大的危害,攻击者可以利用它读取、修改或者删除数据库内的数据,获取数据库中的用户名和密码等敏感信息,甚至可以 获得数据库管理员的权限。
导读:SQL Injection 原理
如果能够再利用SQLServer扩展存储过程和自定义扩展存储过程来执行一些系统命令,攻击者还可以获得该系统的控制权。而且,SQL Injection 也很难防范。网站管理员无法通过安装系统补丁或者进行简单的安全配置进行自我保护,一般的防火墙也无法拦截SQL Injection 攻击。
如下面的用户登陆验证程序:
$sql = "SELECT * FROM user WHERE username='$username' AND password='$password'"; $result = mysql_db_query($dbname, $sql);
如果我们提交如下url:
http://127.0.0.1/injection/user.php?username=angel' or '1=1
那么就可以成功登陆系统,但是很显然这并不是我们预期的,同样我们也可以利用sql的注释语句实现sql注入,如下面的例子:
http://127.0.0.1/injection/user.php?username=angel'/* http://127.0.0.1/injection/user.php?username=angel'%23
这样就把后面的语句给注释掉了!说说这两种提交的不同之处,我们提交的第一句是利用逻辑运算,第二、三句是根据mysql的特性,mysql支持/*和#两种注释格式,所以我们提交的时候是把后面的代码注释掉,值得注意的是由于编码问题,在IE地址栏里提交#会变成空的,所以我们在地址栏提交的时候,应该提交%23,才会变成#,就成功注释了, 这个比逻辑运算简单得多了。
一、SQL注入实例
$unsafe_variable = $_POST['user_input']; mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");
当POST的内容为:
value'); DROP TABLE table;--
以上的整个SQL查询语句变成:
INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')
二、防止SQL注入措施
1.Use prepared statements and parameterized queries.
SQL语句和查询的参数分别发送给数据库服务器进行解析。这种方式有2种实现:
(1)使用PDO(PHP data object)
$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name'); $stmt->execute(array('name' => $name)); foreach ($stmt as $row) { // do something with $row }
(2)使用MySQLi
$stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?'); $stmt->bind_param('s', $name); $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { // do something with $row }
2.对查询语句进行转义(最常见的方式)
$unsafe_variable = $_POST["user-input"]; $safe_variable = mysql_real_escape_string($unsafe_variable); mysql_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')");
Warning: As of PHP 5.5.0 mysql_real_escape_string and the mysql extension are deprecated. Please use mysqli extension and mysqli::escape_string function instead
$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();
3.限制引入的参数
$orders = array("name","price","qty"); //field names $key = array_search($_GET['sort'],$orders)); // see if we have such a name $orderby = $orders[$key]; //if not, first one will be set automatically. smart enuf :) $query = "SELECT * FROM `table` ORDER BY $orderby"; //value is safe
4.对引入参数进行编码
SELECT password FROM users WHERE name = 'root' --普通方式 SELECT password FROM users WHERE name = 0x726f6f74 --防止注入 SELECT password FROM users WHERE name = UNHEX('726f6f74') --防止注入
set @INPUT = hex("%实验%"); select * from login where reset_passwd_question like unhex(@INPUT) ;
There was some discussion in comments, so I finally want to make it clear. These two approaches are very similar, but they are a little different in some ways:0x prefix can only be used on data columns such as char, varchar, text, block, binary, etc. Also its use is a little complicated if you are about to insert an empty string. You'll have to entirely replace it with '', or you'll get an error.UNHEX() works on any column; you do not have to worry about the empty string.
5.使用MySQL存储过程其他:验证输入参数
http://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php http://stackoverflow.com/questions/18026088/pdo-sends-raw-query-to-mysql-while-mysqli-sends-prepared-query-both-produce-the