浅析SQL注入-阿里云开发者社区

开发者社区> 科技小能手> 正文

浅析SQL注入

简介:
+关注继续查看

一、SQL注入原因

SQL漏洞出现的原因大家都应该知道了,还是哪一句熟悉的话:用户输入的数据被SQL解释器执行。

SQL注入的原因和分类都是很简单的,难的是对可能出现SQL注入的地方进行细致拼接测试。


二、SQL注入漏洞分类

2.1 数字型注入

数字型注入是最初级的注入,常出现在ASP、PHP等弱类型语言之中,因为弱类型语言会自动推导变量类型。

示例:

1
http://localhost/sql.php?id=8 AND 1=1

上述的示例多是进行自动化的“盲注”。在后台执行的SQL为:SELECT * FROM test where id  8 AND 1=1。

PS:盲注是在服务器没错误回显时完成的注入攻击。服务器没有错误回显,对于攻击者而言缺少了非常重要的“调式信息”,所以攻击者需要找一个一个方法来验证注入的SQL是否已经执行。盲注是根据多给条件进行判断,如果页面没有出错则表示存在注入点。


2.2 字符型注入

字符型与数字型的最大区别在于,前者一般要是有单引号来闭合,后者不需要。

示例:

1
http://localhost/sql.php?name=admin and 1=1

这样是无效,因为后端的SQL为:

     

1
SELECT FROM test where name 'admin and 1=1'

如果改为:

1
http://localhost/sql.php?name='admin' and 1=1

此时后端SQL:SELECT * FROM test where name = 'admin' and 1=1

该类型的注入是公司扫雷重点照顾对象,大家可以看看扫雷的日志多是各种拼接的SQL。


总结一下,字符型注入还可以细分出一下不同的类型,如POST注入、Cookie注入、搜索注入、BASE64注入。。。本质上还是字符型注入,数字型注入也是可以说是特殊的字符型注入。

因为公司已经存在强大的扫雷工具了所以在此就不再介绍别的工具了。


三、防止SQL注入

防SQL注入总结就一句话:有输入的地方就有存在SQL的风险。

3.1 统一输入处理,严格类型判断

金融知心的大多数的项目使用的PHP,弱类型的语言没有强制要求处理数据类型。但防御数字型注入还是很简单的,一个函数 intval ($param);就可以。

1
$param  intval ($param);

3.2 特殊字符转义

对于字符类型,他们都是string,所以很难判断输入的是否存在恶意攻击。现在通用的防御方法就是对特殊符号进行转义。

1
$paramStr = mysql_real_escape_string($paramStr);

最好是框架或者类库在底层提供了而不需要开发人员在业务代码中混合在一起了。

3.3 使用预编译

PHP的PDO也提供了预编译的功能了,只是在我们金融项目中很少使用,因为使用起来不算方便。

3.4 使用框架

在PHP中很多框架都是提供了好用而且安全的数据库操作类库了,知心普遍使用的Topaz使用的mysqli而且SQL语句都是拼接的,所以最近扫雷就会出现类似SQL注入的出现。

3.5 使用存储过程

不建议使用了,虽然使用存储过程可以提高执行效率,因为使用存储过程需要精通SQL,而且不方便经常变更和会出现移植问题。


四、举例说明

最近扫雷经常出现提示有SQL注入的情况,也有的是误报的。也执行到了数据库,仅是此次组装的SQL是错误的(谁知道如果是人工构造时候会不会出现真的注入了呢)。为了安全的考虑,是不允许不符合格式的SQL进入数据库执行的,不论这个语句是否可以真的注入。有可能是SQL漏洞被发觉的是因为我们异常错误的处理不当,不应该再给前端返回后端数据库异常的信息。

出现多次扫雷问题,主要是对参数校验不足和库类使用的方式造成。

如我们看一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 public static function getLoanArticle ($inputarray $arrIds$bsPriceList$cate$nestId = 22){
        $rtn array();
         
        $db = Env::getDB('fnbiz');
         
        $ids array();
        foreach ($arrIds as $id)
        {
            $id $db->real_escape($id);
            if (!empty($id)) {
                $ids[] = $id;
            }
        }
 
        if (empty($ids))
        {
            Env::getLogger()->warning('DB''empty parameter arrIds');
            return $rtn;
        }
 
        //TODO delete note 
        $tbl 'knowledge_loan_article';
        $strId = implode(','$ids);
         //TODO: select count
        $sql "SELECT articleId, keywords, source, title, brief, lastUpdateTime, articleLink, content, ext FROM $tbl WHERE articleId IN ($strId) AND isDelete = 0 AND nestId = $nestId";
        Env::getLogger()->trace(
                "get articel from db [sql:$sql] [articleId count:" count($ids) .
                         "]");
         
        //$rs = $db->fetchAll($sql);
        ...  ...


       

    为什么写成这样SQL拼接的方式,是因为Topaz要求这么写的,但在这个SQL语句之前没有对$id进行校验就会有SQL注入。很庆幸,扫雷发现并进行处理了。参数的校验包含了参数类型和参数长度等多种属性的校验。注:安全与成本是成反比的,注意平衡!

    使用UI的一段代码来看看:

    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public static function getByProductIds(array $arrIds) {
        if (empty($arrIds)) {
            Env::getLogger()->warning('DB''empty parameter arrIds');
            return array() ;
        }
        $db = Env::getDB('fnbiz');
        $ids array() ;
        foreach($arrIds as $id ){
            $ids[] = $db->real_escape($id) ;
        }
 
        $strIds = implode(",",$ids) ;
        $tb "product";
        $sql "SELECT * FROM `$tb` WHERE productId IN ( $strIds )";
        $res$db->fetchAll($sql) ;
 
        $mapRes array() ;
        foreach($res as $item){
            $mapRes[$item['productId']] = $item;// json_decode($item['productInfo'], true) ;
        }
        $rtn array() ;
        foreach($ids as $id){
            if( !isset($mapRes[$id]) ) {
                Env::getLogger()->warning('DB',"product $id not found in db") ;
            }else{
                 $rtn[$id] = $mapRes[$id] ;
            
        }
        return $rtn ;
    }

    可以发现参数的转义已经和业务的代码混合在一起了,每一个人的代码风格都不一样这并不可怕,可怕的是每一个人开发人员的安全意识都不一样。有的有参数的转义有的却没有!

    

    建议使用PDO库类替换Topaz并统一语法。



本文转自 梦朝思夕 51CTO博客,原文链接:http://blog.51cto.com/qiangmzsx/1662639

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
怎么设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程
6943 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
4504 0
使用OpenApi弹性释放和设置云服务器ECS释放
云服务器ECS的一个重要特性就是按需创建资源。您可以在业务高峰期按需弹性的自定义规则进行资源创建,在完成业务计算的时候释放资源。本篇将提供几个Tips帮助您更加容易和自动化的完成云服务器的释放和弹性设置。
7777 0
阿里云服务器安全组设置内网互通的方法
虽然0.0.0.0/0使用非常方便,但是发现很多同学使用它来做内网互通,这是有安全风险的,实例有可能会在经典网络被内网IP访问到。下面介绍一下四种安全的内网互联设置方法。 购买前请先:领取阿里云幸运券,有很多优惠,可到下文中领取。
9436 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,云吞铺子总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系统盘、创建快照、配置安全组等操作如何登录ECS云服务器控制台? 1、先登录到阿里云ECS服务器控制台 2、点击顶部的“控制台” 3、通过左侧栏,切换到“云服务器ECS”即可,如下图所示 通过ECS控制台的远程连接来登录到云服务器 阿里云ECS云服务器自带远程连接功能,使用该功能可以登录到云服务器,简单且方便,如下图:点击“远程连接”,第一次连接会自动生成6位数字密码,输入密码即可登录到云服务器上。
16868 0
阿里云ECS云服务器初始化设置教程方法
阿里云ECS云服务器初始化是指将云服务器系统恢复到最初状态的过程,阿里云的服务器初始化是通过更换系统盘来实现的,是免费的,阿里云百科网分享服务器初始化教程: 服务器初始化教程方法 本文的服务器初始化是指将ECS云服务器系统恢复到最初状态,服务器中的数据也会被清空,所以初始化之前一定要先备份好。
3235 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
1133 0
14491
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载