SQL注入修复建议—Hack之路

SQL注入漏洞防护
    SQL注入是最危险的漏洞之一 ,但也是最好防护的漏洞之一。本文章将介绍在PHP的编码中合理的使用MySQL提供的预编译进行SQL注入防护,在PHP中使用PHP数据对象扩展或MySQL扩展链接数据库,并且对SQL语句进行预编译处理。如果在一些项目中无法使用预编译来防止SQL注入,可以采用传统方法来验证用户的输入是否合法,严格控制输入参数的数据类型,过滤非法字符,拦截带有SQL语法的参数传入应用程序,在一定程度上提高恶意攻击者的攻击成本,但是往往容易被绕过,常用的SQL注入漏洞的修复方法有两种
   
MySQL预编译处理
   一个完整的MySQL预编译处理分为编译,执行,释放三步,预编译遵循指令和数据分离的原则,可以有效的防止SQL注入的发生,首先是编译,通过PREPARE stmt_name FROM preparable_stm 来预编译一条SQL语句。

mysql>prepare test from ‘insert into hacker select ?,?,?,?’;
Query OK,0 rows affected (0.00sec)
Statement prepared

通过EXECUTE stmt_name [USING @var_name [,@var_name]…]的语法来执行预编译语句。

mysql>sete @name=’hacker’,@email=’hello@ptpress.com.cn’,@password=’asdfghjkl’,@status=1;
Query OK,0 rows affected (0.00sec)
mysql>execute test using @name,@email,@password,@status;
Query OK,1 row affected (0.01sec)
Records:1 Duplicates: 0 Warnings:0
mysql> select * from hacker;
|   id  |   name   |   email    |    password   |    status    |
————————————————————————
|   1   |   hacker  |   hello@ptpress.com.cn|   asdfghjkl|    1     |
————————————————————————
1 row in set (0.00sec)

可以看到,数据以及被成功的插入表中。
MySQL中的预编译语句作用域是会话级的,但可以通过max_prepared_stmt_count变量来控制全局最大储存的预编译语句

mysql>set @@global.max_prepared_stmt_count=1
Query OK, 0 row affected (0.00 sec)
mysql> prepare selecttest from ‘select * from t’
ERROR 1461 (42000):Can’t create more than max_prepared_stmt_count
statements (current value:1)

当预编译条数达到阈值时,可以看到MySQL会报出如上所示的错误。
如果要释放一条预编译语句,则可以使用{DEALLOCATE | DROP} PREPARE stmt_name 的语法进行操作

mysql>deallocate prepare test;
Query OK,0 rows affected (0.00 sec)

校验和过滤
为了有效防止SQL注入,应尽量使用MySQL的预编译处理,不要使用动态拼装SQL。如果既有的系统已经存在一些历史代码动态拼装SQL的情况,并且业务逻辑复杂,不能及时的更改为预编译处理形式,或者PHP版本较低,数据库版本比较老的情况,不支持预编译处理,为了防止前文提到的普通注入,隐式类型注入,盲注,二次解码注入,需要对输入的数据进行有效检验和过滤。通常使用的校验方式是判断传入的数据类型是否合法,如果不上所需要的要及时中断程序,防止继续执行。下面的示例中对传入的数据类型进行判定

<? php
$id = $_GET[‘id’];
if(empty($id)){
die(‘参数不能为空,请重新输入!’);
}
if(gettype($id)! = ‘integer’){
die(“非法的数据类型,请重新输入!”);
}
if($id<=0){
die(“输入的数据超出范围内,请重新输入!”);
}

 

下列是一些常用的校验变量函数,这些函数通常用于校验用户传入的参数。
———————————————————
gettype() |  获取变量的类型
is_float()  |  检测变量是否是浮点型
is_bool()  |  检测变量是否是布尔型
is_int()     |   检测变量是否是整数
is_null()   |   检测变量是否为NULL
is_mumeric  |    检测变量是否为NULL
is_object  |   检测变量是否是一个对象
is_resource()  |  检测变量是否为资源类型
is_scalar()  |   检测变量是否是一个标量
is_string()  |   检测变量是否存在字符串
is_array()   |    检测变量是否是数组
filter_var()  |    使用特定的过滤器过滤一个变量
———————————————————-

除了上面的这些函数之外,页面可以使用正则过滤SQL语句中的非法字符防止发生部分SQL注入方式,下面是代码示例

<?php
function removeSpecialChar($param){
$regex = “/ \/ | \ ~ | \ ! | \ @ | \ \ $ | \ % | \^| \ & | \ * | \ ( | \ ) | \ _ | \ + | \ { | \ } | \ :  | \ <| \> | \ ? | \ [ | \ ] | \ . | \ .| \/ | \ ; | \  ‘ | \ ‘ | \ – | \ = | \ \ \ | \ | /”;
return preg_replace($regex, “”,$param);
}
$name = “name’  OR  ‘a’ = ‘a’ “;
$name = removeSpecialChar ($name);
?>

同时还可以检查参数中是否包含SQL关键字,下面是示例代码。

<?php
eregi(‘select | insert | update | delete | drop | truncte | ‘ | /* | * | ../ |./ | union | into | load_file |outfile |union’,$name);
?>

这些过滤方式都需要在特定业务场景下使用,使用不当可能会影响到现有业务。要根本上杜绝SQL注入漏洞,建议使用SQL预编译处理进行系统研发

宽字节注入防护
要防止这类整型的宽字节注入,可以在进行SQL查询前使用intaval对变量进行强制转换。可以使用mysql_real_escape_string 进行防御,在使用前需要 mysql_set_charset 指定当前所使用的字符集格式才能生效。

XML注入漏洞防护
  XML注入攻击也成为XXE漏洞,XML文件的解析依赖于libxml库,libxml 2.9及以前的版本默认支持并开启的外部引用,服务端解析用户提交的XML文件时未对XML文件引用的外部实体进行核实的处理,并且实体的URL 支持 file:// 和 php:// 等协议,攻击者可以在XML文件中声明URI指向服务器本地造成攻击。XEE漏洞一旦被攻击者利用,可以读取服务器任意文件,执行任意代码,发起DDOS攻击。在XML中引入外部实体一定要注意其安全性,需要进行严格检查,或者引入
(1) 对用户的输入进行过滤,如<,>、‘、“、 &等
(2) 常见的XML解析方法有DOMDocument , SimpleXML,XMLReader , 这三者都基于 libxml 库解析 XML , 所以均受影响。xml_pares() 函数则基于 expact 解析器,默认不载入外部DTD,不受影响。可以在PHP解析XML文件之前使用 libxml_disable_entity_loader(true)来禁止加载外部实体,并使用libxml_use_internal_errors()禁止报错


网站地址:https://www.hackzl.cn;发布者:hack之路,转转请注明出处:https://www.hackzl.cn/index.php/2020/09/24/sql%e6%b3%a8%e5%85%a5%e4%bf%ae%e5%a4%8d%e5%bb%ba%e8%ae%ae-hack%e4%b9%8b%e8%b7%af/

发表评论

邮箱地址不会被公开。 必填项已用*标注