博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
网络安全系列 之 SQL注入学习总结
阅读量:7179 次
发布时间:2019-06-29

本文共 5456 字,大约阅读时间需要 18 分钟。

目录

1. sql注入概述

程序里面如果使用了未经校验的外部输入来构造SQL语句,就很可能会引入SQL注入漏洞。

注入攻击

对于字符串输入,如果这个字符串将被解释为某种指令,那么需要特别注意防止注入攻击。sql注入、os命令注入、xml注入是典型的攻击类型。

2. sql注入测试工具

可以使用BurpSuite工具,浏览器上修改代理设置为burp工具配置的代理监听的IP端口。

对浏览器发送的请求进行拦截并修改其中参数,尝试注入攻击。

  • sleep盲注: 返回时间>=5s,存在注入.
    {"stationCodes":"AD02C7CCAB6F4BF9A85BC010AF16AC62')xor(sleep(5))and('","ptIds":"","pmYearDate":"2018","page":1,"pageSize":10}
  • 普通注入or /and : id="1' or '1'='1" id="1' or '1'='2"
  • 报错注入: updatexml /extractvalue 、floor后group by。
  1. id=1 and updatexml(1,concat(0x7e,version(),0x7e),1) 返回version(),存在注入.
  2. id=1 and extractvalue(1,concat(0x7e,version()) 返回version(),存在注入.
  3. id=1 and (select 1 from (select count(),concat(version(),floor(rand(0)2))x from information_schema.tables group by x)a)
    返回version(),存在注入.

3. sql注入防御方法

3.1 问题来源

  1. 执行外部数拼接的SQL语句。
  2. 执行外部传入的整条SQL语句
  3. 在配置文件中的SQL语句没有使用预编译方式占位符。
  4. 校验函数有缺陷或占位符使用错误。

3.2 防御方法

  1. 使用参数化语句

    sql语句预编译绑定变量,不直接拼接。

  2. 输入校验
    采用白名单或黑名单方式对入参进行检查。
    备注:ESAPI(Enterprise Security API)也提供了输入验证类 org.owasp.esapi.reference.DefaultValidator的实现。
  3. 输出编码
    在sql注入语境中,将发送给数据库的内容进行编码(或转义)是必需的操作,可以保证内容被正确的处理。
    针对Mysql的编码举例:在动态sql中提交的信息(LIKE语句中使用通配符的位置)添加引用。
sql = sql.replace("%",“\%”);   //%匹配0个或多个任意字符    sql = sql.replace("_",“\_”);    //_匹配任意一个字符

备注:在动态sql和拼接sql场景下也可以利用ESAPI进行转义处理

// ESAPI转义,防SQL注入    public static String encodeForSql(String input) {        MySQLCodec mysqlCodec = new MySQLCodec(MySQLCodec.Mode.STANDARD);        return ESAPI.encoder().encodeForSQL(mysqlCodec, input);    }    // 说明: esapi需要有两个配置文件:ESAPI.properties、validation.properties

小结:输入校验输出编码是处理注入问题(如xss)的一贯套路。

4. SQL注入防御举例

4.1 使用JDBC时,SQL语句进行了拼接

1. 使用statement的executeQuery、execute、executeUpdate等函数时,传入的SQL语句拼接了来自外部的不可信参数。
**错误示例**    String userName = ctx.getAuthenticatedUserName(); //this is a constant    //itemName是外部读入的参数拼接到SQL语句    String sqlString = "SELECT * FROM t_item WHERE owner='" + userName + "' AND itemName='" + request.getParameter("itemName") + "'";    stmt = connection.createStatement();    rs = stmt.executeQuery(sqlString);

解决方法 1) 使用预编译方式(不可信数据作为字段值); 2) 对拼接到SQL语句中的外部参数进行白名单校验(不可信数据作为表名,字段名,排序方式)。

**正确示例**:使用白名单校验方式校验itemName    String userName = ctx.getAuthenticatedUserName(); //this is a constant    String itemName=getCleanedItemName(request.getParameter("itemName"));    String sqlString = "SELECT * FROM t_item WHERE owner='" + userName + "' AND itemName='" + itemName + "'";    stmt = connection.createStatement();    rs = stmt.executeQuery(sqlString);
2. 使用connection的PreparedStatement时,使用的SQL语句拼接了来自外部的不可信参数。
**错误示例**    String userName = ctx.getAuthenticatedUserName(); //this is a constant    //itemName是外部读入的参数拼接到SQL语句    String itemName = request.getParameter("itemName");    // ...Ensure that the length of userName and itemName is legitimate    // ...    String sqlString = "SELECT * FROM t_item WHERE owner=? AND itemName='"+itemName+"'";    PreparedStatement stmt = connection.prepareStatement(sqlString);    stmt.setString(1, userName);    rs = stmt.executeQuery();

解决方法 1) 将拼接方式改为占位符方式; 2). 对拼接到SQL语句中的外部参数进行白名单校验。

**正确示例**:所有的参数使用占位符    String userName = ctx.getAuthenticatedUserName(); //this is a constant    String itemName = request.getParameter("itemName");    // ...Ensure that the length of userName and itemName is legitimate    // ...    String sqlString = "SELECT * FROM t_item WHERE owner=? AND itemName=?";    PreparedStatement  stmt = connection.prepareStatement(sqlString);    stmt.setString(1, userName); // jdbc编号从1开始    stmt.setString(2, itemName);    rs = stmt.executeQuery();
3. 存储过程使用动态方式构建SQL语句,导致SQL注入风险。
**错误示例**REATE PROCEDURE sp_queryItem    @userName varchar(50),    @itemName varchar(50) AS BEGIN     DECLARE @sql nvarchar(500);     SET @sql = 'SELECT * FROM t_item                 WHERE owner = ''' + @userName + '''                AND itemName = ''' + @itemName + '''';    EXEC(@sql); END GO

解决方法 采用参数化查询的方式

**正确示例**:采用参数化查询的方式CREATE PROCEDURE sp_queryItem    @userName varchar(50),     @itemName varchar(50) AS BEGIN     SELECT * FROM t_item      WHERE userName = @userName    AND itemName = @itemName; END GO

4.2 使用Hibernate时,调用API时,传入的SQL语句有拼接外部参数

1. 调用createQuery时,传入的SQL语句拼接了来自外部的不可信参数。
**错误示例**    //SQL语句拼接不可信参数    String itemName = request.getParameter("itemName");    Query hqlQuery = session.createQuery("from Item as item where item.itemName = '" + itemName + "'");    List
hrs = (List
) hqlQuery.list();

解决方法 1) 对拼接到SQL语句中的外部参数进行白名单校验; 2) 使用hibernate的配置映射关系方式。

**正确示例**:对外部参数进行白名单校验    String itemName = request.getParameter("itemName");    itemName=getCleanedItemName(itemName);//白名单校验    Query hqlQuery = session.createQuery("from Item as item where item.itemName = '" + itemName + "'");    List
hrs = (List
) hqlQuery.list();

4.3 使用MyBatis时,SQL语句使用$占位符

1. 配置文件使用$占位符
错误示例:    // 使用$,底层将使用简单拼接        

解决方法 1) 将$占位符改为#占位符; 2) 如果外部不可信数据作为表名,字段名,排序方式,则对外部参数进行白名单校验。

**正确示例**:使用#占位符方式    
2. mybatis接口中的函数标签的SQL语句,使用了$占位符
**错误示例**    public interface IUserDAO {      //标注中的SQL语句通过$表示占位符,内部实现是单纯的拼接    @Select("select *from User where id=${id})         User getUser(@Param("id")String id);    }
**正确示例**:标注中的SQL语句通过'#'表示占位符,内部实现是参数化预处理    public interface IUserDAO {     @Select("select *from User where id=#{id})        User getUser(@Param("id")String id);    }

end.

2018.03.31

转载于:https://www.cnblogs.com/eaglediao/p/8547751.html

你可能感兴趣的文章
巴菲特正寻求可再生能源领域的投资机会
查看>>
《Android程序设计》一3.4 静态应用资源和上下文
查看>>
固态硬盘SSD在关键场合的应用
查看>>
详述机柜的不同分类及常见配件
查看>>
CWA成员称其领导人被捕后将增加对美国政府的攻击
查看>>
谭铁牛当选CVPR 2021大会主席,华人学术力量不容小觑
查看>>
中诚信携手神州控股助推智慧城市到信用城市发展
查看>>
想用好云?先看看这10条安全建议
查看>>
数据中心电源仍然困扰着CIO
查看>>
美南方电力解围东芝西屋困局 计提损失将减一半生 “蝴蝶效应”
查看>>
自然语言处理顶级会议 EMNLP 最佳论文出炉,聚焦神经网络 (下载)
查看>>
视频矩阵的十二种特性是什么
查看>>
智能电网易遭受网络攻击的症结在哪里?
查看>>
微软推视频分析服务 片中人什么心情都知道
查看>>
Windows 10年度更新将启用Hotspot 2.0功能
查看>>
雾计算是炒作吗?
查看>>
IT企业开始为NFV热身
查看>>
Win10或成全球最大操作系统
查看>>
智能城市包罗万象 “独干”成不了气候
查看>>
乌云和漏洞盒子停业整顿:白帽子被抓是导火索?
查看>>