漏洞解决方案-SQL注入攻击

漏洞解决方案-SQL注入攻击

  • 前置知识
  • 修复方案
  • 代码参考

前置知识

SQL注入攻击,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。


威胁描述:
如果SQL注入成功,攻击者可以获取系统数据库的信息,可以修改删除数据库,还可能获取执行命令的权限,进而完全控制服务器。
涉及功能点:
任何涉及数据库连接的功能点,如用户登录、查询、数据修改、删除等功能。

修复方案

防范SQL注入,标准方案为输入验证与参数化查询相结合。
输入验证分为白名单和黑名单两种方式,通常在系统中是结合到一起来完成输入验证,具体实现通过正则表达式来完成。需要注意以下几方面:

  • 在可信系统(比如:服务器)上执行所有的数据验证。
  • 验证所有来自不可信数据源(比如:数据库,文件流,等)的数据。
  • 应当为应用程序应提供一个集中的输入验证机制和规则。
  • 为所有输入明确恰当的字符集,比如:UTF-8。在输入验证前,将数据按照常用字符进行编码(规范化)。如果进行关键字的验证,请先统一大小写。
  • 验证的不仅是参数,包含所有来自客户端的数据,包括:所有参数、URL、HTTP头信息(比如:cookie名字和数据值)。
  • 验证正确的数据类型、验证数据范围、验证数据长度。
  • 请考虑是否允许输入常见危险字符。部分常见的危险字符包括:< > " ’ % ( ) & + \ ’ " 。
  • 特殊字符单独验证:空字节 (%00);换行符 (%0d, %0a, \r, \n);路径替代字符“点-点-斜杠”(…/或…\)。验证替代字符:%c0%ae%c0%ae/ (使用规范化 验证双编码或其他类型的编码攻击)。

代码参考

安全开发实例:

  1. 使用特殊字符过滤程序防护SQL注入攻击:
    代码功能:对HTTP请求中的所有参数进行危险字符过滤,发现危险字符可跳转到相应的错误页面。

    public void doFilter(ServletRequest args0, ServletResponse args1,
                         FilterChain chain) throws IOException, ServletException {
    	HttpServletRequest req=(HttpServletRequest)args0;
    	HttpServletResponse res=(HttpServletResponse)args1;
    	//获得所有请求参数名
    	Enumeration params = req.getParameterNames();
    	String sql = "";
    	while (params.hasMoreElements()) {
    		//得到参数名
    		String name = params.nextElement().toString();
    		//得到参数对应值
    		String[] value = req.getParameterValues(name);
    		for (int i = 0; i < value.length; i++) {
    			sql = sql + value[i];
    		}
    	}
    		//有sql注入和XSS危险字符
    	if (sqlValidate(sql)) {
    		throw new IOException("您发送请求中的参数中含有非法字符:"+sql);
    		//此处可根据系统实际情况进行统一的错误处理,可跳转到error.html
    	} else {
    		chain.doFilter(args0,args1);
    	}
    }
    
    protected static boolean sqlValidate(String str) {
    	str = str.toLowerCase();  //统一转为小写
    	String badStr = "and|exec|insert|select|delete|update|count|union|master|truncate|char|declare|cast|set|fetch|varchar|sysobjects|drop|`|'|\"|<|>|(|)|/|\|=|+|-|#|*|;|%";  //过滤掉的sql注入和XSS的关键字,可以手动添加和修改
    	String[] badStrs = badStr.split("\\|");
    	for (int i = 0; i < badStrs.length; i++) {
    		if (str.indexOf(badStrs[i]) >= 0) {
    			return true;  //参数中包含要过滤关键字;
    		}
    	}
    	return false;	//参数中不包含要过滤关键字;
    }
    
  2. 通过参数化查询方式进行SQL注入攻击防护:

    String sql = “select * from product where cat=?’ and price >?’”;  //创建包含参数占位符的SQL语句
    PreparedStatement pstmt = con.prepareStatement(sql);	//创建PreparedStatement对象
    pstmt.setInt(1, request.getParameter(“cat”));	//设置参数一类型和取值
    pstmt.setString(2, request.getParameter(“price”));	//设置参数二类型和取值
    ResultSet rs = pstmt.executeQuery();	//返回查询结果
    
  3. 使用MyBatis技术,通过Mapper.xml文件定义SQL语句进行SQL注入攻击防护:

    <mapper namespace="TestUser">	//命名空间
    <select id="getById" parameterType="java.lang.String"
          resultMap="TestFlowResult">
          select
          <include refid="TestFlowColumns" />
          <![CDATA[
            from TEST_TABLE
            where
               INSPECT_ID = #{id} 
          ]]>
    </select>
    </mapper>
    

    在编写mybatis的映射语句时,尽量采用“#{xxx}”这样的格式。若不得不使用“${xxx}”这样的参数,要手工地做好过滤工作,来防止sql注入攻击。

  4. 强类型的参数化查询,即在数据库增加、查询、更新操作时,sql语句中所有输入参数统一采用#param#方式。示例如下:

    <update id="updatePtaskDetailState" parameterClass="java.lang.String">
    	update ZX_PTASKDETAIL set BATCHJNLNOSTATE = '4' where JNLNO = #jnlNo#
    </update>
    

    需要使用like语句的地方可以使用’%’||#param#||’%‘或concat(concat(’%’,#param#),’%’)避免注入。示例如下

    select * from ZX_PCIF where name like '%'||#name#||'%'
    

关注公众号,一起分享实用安全技术,关注安全最新事件,记录工作常见问题,吐槽生活真心操蛋。
漏洞解决方案-SQL注入攻击_第1张图片

你可能感兴趣的:(安全,安全漏洞)