SQL注入原理
SQL注入漏洞存在的原因,就是拼接SQL参数
例:参数为id
$sql = 'select * from test where id='.$_GET['id'];
正常输入2
则sql为:select * from test where id=2;
只会查出id为2的记录
黑客输入2 or 1=1
则sql为select * from test where id=2 or 1=1;
这样就会输出test中所有的数据,就完成了一次sql注入
例:登录输入用户名username和密码password
$username = $_POST['username'];
$password = md5($_POST['password']);
//拼接sql
$sql="select * from test where username='".$username."' and password='".$password."'";
正常输入用户名ceshi和密码123456
则sql为select * from test where username='ceshi' and password='e10adc3949ba59abbe56e057f20f883e';
只会查出用户名为ceshi和password为123456的记录
黑客输入用户名ceshi' or 1=1 --和密码123456
则sql为select * from test where username='ceshi' or 1=1 -- ' and password='e10adc3949ba59abbe56e057f20f883e'
这样查询的时候就相当于执行的sql为select * from test where username='ceshi' or 1=1,因为'--'注释了后面的sql
这样又完成sql注入
sql注入的防范
1,预编译和参数化(重点)
- 使用PDO
$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name'); $stmt->execute(array(':name' => $name)); foreach ($stmt as $row) { // do something with $row }
- 使用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 }
原理:采用上述方法,会将sql语句:'select * from employees where name = ?'预先编译好,也就是
sql引擎会预先进行语法分析,
产生语法树,生成执行计划
也就是说,后面输入的参数,无论输入什么,
都不会影响该sql语句的语法结构了
,即后面的输入的参数即使包含sql关键字(update select and or...)
也不可能当作sql命令来执行,只会被当作字符转字面值参数,所以sql语句预编译可以防御sql注入
2,字符串过滤
- 在php.ini中开启magic_quotes_gpc on,对输入进行转义
- 使用函数对输入进行sql关键字过滤