sql语句预编译
例如:
String sql = "select id, no from user where id=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, id);
ps.executeQuery();
这里采用了PreparedStatement
,就会将sql语句预先编译
好,也就是SQL引擎会预先进行语法分析,产生语法树,生成执行计划,也就是说,后面你输入的参数,无论你输入的是什么,都不会影响该sql语句的 语法结构了,因为语法分析已经完成了,而语法分析主要是分析sql命令,比如 select ,from ,where ,and, or ,order by
等等。所以即使你后面输入了这些sql命令,也不会被当成sql命令来执行了,因为这些sql命令的执行, 必须先的通过语法分析,生成执行计划,既然语法分析已经完成,已经预编译过了,那么后面输入的参数,是绝对不可能作为sql命令来执行的,只会被当做字符串字面值参数。所以sql语句预编译可以防御sql注入
讲一下另外一个预编译,就是用PDO,这里就推荐几篇文章自己看一下,简单说一下就是原理跟上面的差不多,把执行语句和变量分开,变量分别绑定,分别传参,从而阻止了注入,只是底层不太明了,自己真菜。。
https://segmentfault.com/q/1010000000723496
http://www.cnblogs.com/zl0372/p/php_28.html
https://blog.csdn.net/theVicTory/article/details/62884352
预编译方法就最有效!!也是如今市场上最流行的方式了
检查变量数据类型和格式
例如:
$uid=checkuid($uid); //检测$uid是不是数字类型,不是不继续往下运行
$sql = "SELECT uid,username FROM user WHERE uid='{$uid}‘;
这段语句是为了保证了id是数字类型,checkid是一个自定义
的函数,但是千万别直接里面写一个is_numeric
就结束了啊,这很容易就可以用16进制或者是科学计数法去绕过的,这个还是少用吧,毕竟自写函数就像是写黑名单,肯定会有纰漏的
过滤特殊字符
这个方法也相当于黑名单
,还是少用为好,一般有纰漏就可以去绕过的了
例如:
public static boolean sql_inj(String str)
{
String inj_str = “’|and|exec|insert|select|delete|update|
count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+|,”;
String inj_stra[] = split(inj_str,”|”);
for (int i=0 ; i < inj_stra.length ; i++ )
{ if (str.indexOf(inj_stra[i])>=0) { return true; }
}
return false;
}
黑名单只能追求全面去避免SQL注入了
转译特殊符号
例如:
$uid = isset($_GET['uid']) ? $_GET['uid'] : 0;
$uid = addslashes(uid);
$sql = "SELECT uid,username FROM user WHERE uid='{$uid}'";
这里就是利用了addslashes
函数去对特殊字符进行转义,比如单引号会被转译成\’
,所以无法闭合和注释。不能达到sql注入攻击的效果。一般在CTF题目里面如果我看到这个函数的话,我会预测有75%可能不是SQL注入,先去看看其他点是否存在漏洞
从中间件配置上防止SQL注入
通过启用php.ini配置文件中的magic_quote_gpc (魔术字符)
,就可以将大部分想利用SQL注入漏洞的骇客拒绝于门外。开启magic_quote_gpc=on
之后,能实现addslshes()
和stripslashes()
这两个函数的功能,这就从很大程度上防止了sql注入。PHP 5.4
之前 PHP 指令 magic_quotes_gpc
默认是 on
, 实际上所有的 GET、POST 和 COOKIE 数据都用被 addslashes()
了。 不要对已经被 magic_quotes_gpc
转义过的字符串使用 addslashes()
,因为这样会导致双层转义
。 遇到这种情况时可以使用函数 get_magic_quotes_gpc() 进行检测
但是只开启magic_quote_gpc
,对防止sql注入是远远不够的。
例如以下代码:
$uid = isset($_GET['uid']) ? $_GET['uid'] : 0;
$uid = addslashes(uid);
$sql = "SELECT uid,username FROM user WHERE uid={$uid}";
在这条sql语句中并没有单引号的保护,攻击者既不需要闭合单引号也不需要注释单引号,所以gpc开启对sql注入攻击的防范并没有作用。所以说变量还是要用引号包住才好,别直接就赋值了。。。
通过安全waf去防御
过安全waf达到一定程度防御,软件层面的不多说。
小结
总的来说,现在很多网站多不会再使用字符串拼接去查找数据库里面的内容了,大多数现在使用的是预编译,除了那些荒废的网站以及CTF题目里面会使用,那是不是说以后挖洞挖SQL注入的就比较难了233333。。。我还是太年轻了