一.什么是sql注入
打印下sql发现:
tp代码:
$plat_accountinfo = Db::table("plat_account")->where("accountname='$accountname' and accountpassword='$accountpassword' and isdel=0")->find();
最终转化成原生sql:
SELECT * FROM `plat_account` WHERE ( accountname='admin' or '1'='1' and accountpassword='abe8bbd24e9ccb7595623a512741bc85' and isdel=0 ) LIMIT 1
admin' or '1'='1 这一部分代码里面是个变量,拼接进去正好变成了上面的写法。
二.解决方法1
给用户名密码变量转义下,把里面的',字符前面增加一个\
$accountname = isset($param['accountname']) ? trim($param['accountname']) : '';
$accountpassword = isset($param['accountpassword']) ? trim($param['accountpassword']) : '';
$accountname=addslashes($accountname);
$accountpassword=addslashes($accountpassword);
然后再看下sql:
SELECT * FROM `plat_account` WHERE ( accountname='admin\' or \'1\'=\'1' and accountpassword='abe8bbd24e9ccb7595623a512741bc85' and isdel=0 ) LIMIT 1
$accountname变量内容里面的'被增加了转义字符,’admin\' or \'1\'=\'1 ,这样就被限制住了。
三.解决方法2
tp框架可以把where条件改成数组模式
$where['accountname']=$accountname;
$where['accountpassword']=$accountpassword;
$plat_accountinfo = Db::table("plat_account")->where($where)->find();
最终的sql
SELECT * FROM `plat_account` WHERE `accountname` = 'admin\' or \'1\'=\'1' AND `accountpassword` = 'abe8bbd24e9ccb7595623a512741bc85' LIMIT 1
也能实现类似的效果。
四.解决方法3
//先根据用户名获取密码,然后把传过来的明文密码加密后和数据库取出来的做对比验证
$plat_accountinfo = Db::table("plat_account")->where("accountname='$accountname' and isdel=0")->find();
if($plat_accountinfo['accountpassword']!=$accountpassword){
$rt['sta'] = 0;
$rt['msg'] = "对不起密码不匹配!";
echo json_encode($rt);
die;
}
通过用户名等于admin\' or \'1\'=\'1的方式注入,虽然能取出来一条记录,但是输入密码必须和这条记录的匹配才能验证成功,也能起到预防的效果。