浅析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 ( $input array  $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

相关文章
|
14天前
|
SQL 关系型数据库 MySQL
怎么通过第三方库实现标准库`database/sql`的驱动注入?
在Go语言中,数据库驱动通过注入`database/sql`标准库实现,允许统一接口操作不同数据库。本文聚焦于`github.com/go-sql-driver/mysql`如何实现MySQL驱动。`database/sql`提供通用接口和驱动注册机制,全局变量管理驱动注册,`Register`函数负责添加驱动,而MySQL驱动在`init`函数中注册自身。通过这个机制,开发者能以一致的方式处理多种数据库。
|
20天前
|
SQL 安全 关系型数据库
SQL 注入神器:SQLMap 简单使用
SQL 注入神器:SQLMap 简单使用
|
28天前
|
SQL 存储 Java
如何避免SQL注入攻击?
如何避免SQL注入攻击?
|
1月前
|
SQL 安全
jeecg-boot sql注入漏洞解决
jeecg-boot sql注入漏洞解决
115 0
|
1天前
|
SQL 数据库
sql注入方式
sql注入方式
7 0
|
1天前
【干货】sql-labs、请求方式、注入类型、拼接方式
【干货】sql-labs、请求方式、注入类型、拼接方式
5 0
|
1天前
|
SQL 开发框架 安全
【干货】如何判断 Sql 注入点
【干货】如何判断 Sql 注入点
9 1
|
1天前
|
SQL 安全 PHP
基于PHPCMS的SQL注入(Havij)
基于PHPCMS的SQL注入(Havij)
10 1
|
3天前
|
SQL 安全 Java
Spring Boot中的跨站点脚本攻击(XSS)与SQL注入防护
【6月更文挑战第15天】在现代Web应用程序开发中,安全性是一个至关重要的课题。跨站点脚本攻击(XSS)和SQL注入是最常见的两种攻击类型,它们可以严重威胁到应用程序的安全。
20 0
|
15天前
|
SQL 监控 安全
sql注入取数据库
SQL注入是一种攻击技术,用于在SQL查询中注入恶意代码,从而绕过安全措施,获取、修改或删除数据库中的数据。这种行为是非法的,并且严重违反了网络安全和隐私原则。我不能提供关于如何进行SQL注入的指导或