PHP代码安全之SQL注入
1、什么是SQL注入?
SQL攻击(英语:SQL injection),简称注入攻击,是发生于应用程序之数据库层的安全漏洞。简而言之,是在输入的字符串之中注入SQL指令,在设计不良的程序当中忽略了检查,那么这些注入进去的指令就会被数据库服务器误认为是正常的SQL指令而运行,因此遭到破坏或是入侵。
2、SQL注入的高风险情况
- 在代码序中使用字符串连接方式组合SQL语句
- 在应用程序链接数据库时使用权限过大的账户
- 在数据库中开放了不必要但权力过大的功能
- 太过于信任用户所输入的数据,未限制输入的字符数,以及未对用户输入的数据做潜在指令的检查
3、可能造成的危害
- 数据表中数据外泄,导致拖表
- 数据库结构被探知,导致拖库
- 若注入点数据库连接用户有CUD权限,将可能导致被删表
4、避免方法
- 在程序设计时,完全使用参数化查询来进行数据库查询
- 在组合SQL字符串是,先针对所有传入参数进行安全检查
- 使用SQL防注入系统
5、Larave中的SQL注入防范
有经验的PHP后端工程师都知道怎么防范SQL注入,以下内容基本介绍一下一些防范的方法,希望对刚入坑的工程师们有一些帮助。
1)、前端输入的信息都不应该相信,应该做好参数检验
在我们开发php程序的过程中很大部分时间是在和前端的Request请求打交道,我们应该明白所有前端请求都是用可能伪造的,因此我们对于暴露给前端使用的响应程序都应该做好参数合法性校验。
严格校验前端传入参数的还有一大好处就是有效的防止XSS(跨站脚本攻击) 和 CSRF(跨站点伪造请求)。
具体做法可以参照以下范例:
public function fooRequest(Request $request)
{
$validator = Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
if ($validator->fails()) {
return $this->toJson(0, $validator->errors()->first());
}
...
}
2)、在进行数据库操作时尽量使用参数绑定的方式查询
在Laravel中DB的所有操作都是基于PDO进行封装的,PDO本身就提供了安全可靠地参数化查询方法,也就是说PDO的所有用法在Laravel中都有接口实现,我们只需拿来直接使用就行。
如果实在需要进行SQL拼接,除了代码中绝对可靠的变量可以直接用于拼接SQL字串外,其他拼接都必须使用==占位符==传值或者==参数绑定==传值的方式。
具体做法可以参照以下范例:
- DB参数化及字符串拼接查询
//DB查询
$dbRe = DB::table('someTbale')
->where('fields1',$bar1)
->where('fields2','<>',$bar2)
->where('fields3','like','%'.$bar2.'%')
->whereRaw('fields4<? or fields5 > ?',[$fields4,$fields5]) //字串拼接
->get(); //查多条
OR
->first(); //查一条
OR
->update($arrData); //更新
OR
->delete();//删除
- Model参数化及字符串拼接查询
//Model查询
$modelRe = SomeModel::where('fields1',$bar1)
->where('fields2','<>',$bar2)
->where('fields3','like','%'.$bar2.'%')
->whereRaw('fields4<? or fields5 > ?',[$fields4,$fields5]) //字串拼接
->get(); //查多条
OR
->first(); //查一条
OR
->update($arrData); //更新
OR
->delete();//删除
- DB原生SQL字串拼接查询
//原生sql 占位符方式
$dbRe = DB::select('SELECT * FROM someTable WHERE fields1=? AND fields2 <> ?',[$fields1,$fields2]);
OR
$dbRe = DB::update('UDATE someTable set fields1=? WHERE fields2=?',[$fields1,$fields2]);
OR
$dbRe = DB::delete('DELETE FROM someTable WHERE fields1=? AND fields2=?',[$fields1,$fields2]);
//原生sql参数绑定方式
$dbRe = DB::select('SELECT * FROM someTable WHERE fields1=:fields1 AND fields2 <> :fields1',['fields1'=>$fields1,'fields2'=>$fields2]);
OR
$dbRe = DB::update('UDATE someTable set fields1=:fields1 WHERE fields2=:fields2',['fields1'=>$fields1,'fields2'=>$fields2]);
OR
$dbRe = DB::delete('DELETE FROM someTable WHERE fields1=:fields1 AND fields2=:fields2',['fields1'=>$fields1,'fields2'=>$fields2]);