TOC

转载:SQL 注入一点小心得

好久没写技术博客,最近研究产品关于用户体验方面较多,加上项目突然比较多,设计原型、跟进开发、设计师等工作着实没时间写博客。

接下来技术上主要 php 深入学习和 mysql 优化。这两天看了关于 sql 注入方面的知识,拿出来分享一下 :)

登录注入

先看一个我们一般用的登录页面 sql 语句(原生态 php 执行的 sql)

$sql = "select * from users where username = '$username' and password = '$password'";

对于这种 sql,对应一个万能密码和用户名:

万能密码: xx' or 1='1
万能用户名: xx' union select _ from users/_

执行时 mysql 解释为:

$sql = select * from users where username = '$username' and password = ' xx' or 1='1'

不解释,瞬间破解

同样,上面是在 sql 语句中查询字段后的输入值加了单引号,有些时候尤其是初级程序员经常对变量不加单引号:

$sql = "select * from users where username = $username and password = $password";

这时 mysql 解释会被当做数字型字段来匹配

万能密码: 11 union select _ from users/_

执行语句:

select * from users where username = 11 union select * from users/* and password = 54

查询注入

这个比较好理解,一般在页面的搜索框点击按钮搜索时在后台 sql 中可能会用 like 来查询,但如果没有加任何处理,可能输入一个% 或 __ 就会注入到 sql 中查询全部或部分记录,不过在 php 中可以使用一个函数来处理一下:

$keyword = addslashes($keyword); $keword = str_replace("%","\$",$kwyword);

插入注入

我们先模拟一个网站注册页面的 sql 处理语句:

insert into users(username,password,grade) values('frank','123456','1');

假如 users 表中 grade 为等级字段,并且默认字段为 1,注册时用户输入用户名和密码两个字段后,后台插入语句为上面语句,则当用户输入的密码为 123456','3')/*时,执行 sql 为:

insert into users(username,password,grade) values('frank','123456','3')/*,'1';

这样也可以达到注入的目的

解决 SQL 注入

①. 在服务器设置将 php.ini 配置文件中 magic_quotes_gpc 设置为 On

服务器会自动将单引号转义为:\',不过攻击时可以将单引号写为 char(13)-单引号 ASCII 码,也一样可以攻击。

②. 密码比对

通过输入的用户名获取密码,再对密码进行匹配

$sql  = "select * from users where username ='frank'"
$result = mysql_query($sql,$conn);
$row = mysql_fetch_array($result);
if($row['password'] != $password) ...

③. 使用 pdo 的 PDO::prepare()预处理操作

PDO(PHP Data Object)扩展在 PHP5 中加入,PHP6 默认识别 PDO 连接数据库,pdo 相当于是一个数据库抽象层,不同数据库使用相同的方法名,解决数据库连接不同意问题。

工作原理如下:

(使用时需先在 php.ini 中开启对 pdo 扩展的支持)

$sql = "select * from users where username=? and password=?";
// 创建一个pdo对象
$mypdo = new PDO("mysql:host=localhost;port=3306;dbname=xx","root","123456");
// 设置编码
$mypdo->exec("set names utf8");
// 预处理$sql
$pdostatement = $mypdo->prepare(%sql);
// 将用户名和密码填入sql
$pdostatement->execute(array($username,$password));
// 得到查询结果
$result = $pdostatement->fetch();
if(empty($result)) ...

④. 其他企业级解决 sql 注入方式:IDS(入侵检测系统)

关于 sql 注入对于开发工程师来说主要是防守,提高编写安全代码的意识,让我们编写的代码质量更高,安全性方面更好。