详解Web安全---SQL注入漏洞

前言

什么是SQL注入?来看一下下面的案例场景,这是正常情况下的登陆场景:

而当我们使用用户名 ‘:–  的时候,密码随便输入也可以登陆成功!

这时候对比两条sql就能发现,其实用户通过在用户名写入的sql符号将内部sql提前结束,并且将后半句检索条件注释起来达到免密码登陆。

小结:SQL注入就是本来我只有我能操作数据库,本来只是让你输入内容就走,而你却输入命令,从而在我不知情下操作数据库。

手工检测

Web应用的主要注入点有:

  1. POST请求体中的参数;
  2. GET请求头URL中的参数;
  3. Cookie。

闭合类型

1、数字型(%后面跟的是该字符的16进制编码,为了在http中传输特殊字符和汉字等而使用,其中%23表示'#',%20表示空格)

URL:    http://localhost/index.php?id=1
SQL语句:SELECT * FROM users WHERE id=1 LIMIT 0,1

注入语句:http://localhost/index.php?id=1 and 1=1 %23
SQL语句:SELECT * FROM users WHERE id=1 and 1=1 # LIMIT 0,1

2、字符型

URL:    http://localhost/index.php?id=1
SQL语句:SELECT * FROM users WHERE id='1' LIMIT 0,1

注入语句:http://localhost/index.php?id=1' and 1=1 %23
SQL语句:SELECT * FROM users WHERE id='1' and 1=1 #' LIMIT 0,1

3、其他变体

URL:    http://localhost/index.php?id=1
SQL语句:SELECT * FROM users WHERE id=('1') LIMIT 0,1

注入语句:http://localhost/index.php?id=1') and 1=1 %23
SQL语句:SELECT * FROM users WHERE id=('1') and 1=1 #') LIMIT 0,1

字符型注入

测试字符串变体预期结果
N/ A 触发数据库返回错误
’ or ‘1’ = '1 ') or (‘1’ = '1 永真,返回所有行
’ or ‘1’ = '2 ') or (‘1’ = '2 空,不影响返回结果
’ and ‘1’ = '2 ') and (‘1’ = '2 永假,返回空

如果系统限制了某些字符不能输入(前端限制某些字符不可输入至输入框内),我们可以对相关字符进行URL编码转换后尝试绕过,常见需要编码的字符如下:

  • 加号(+)编码为:%2B
  • 等号(=)编码为:%3D
  • 单引号(’)编码为:%27
  • 注释号(#)编码为:%23

数字型注入

测试字符串变体预期结果
N/ A 触发数据库返回错误
or 1 = 1 ) or (1 = 1 永真,返回所有行
or 1 = 2 ) or (1 = 2 空,不影响返回结果
and 1 = 2 ) and (1 = 2 永假,返回空

终止式注入

漏洞修复

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

具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。

1、预编译语句

会产生上面的情况是因为上面的SQL是使用动态拼接的方式,所以sql传入的方式可能改变sql的语义。

动态拼接就是在java中java变量和SQL语句混合使用:

    select * from user where userName=’”+userName+”’ and password = ‘”+password”’

所以要使用 preparedStatement的参数化SQL,通过先确定语义,再传入参数(通过setInt,setString,setBoolean传入参数),就不会因为传入的参数改变sql的语义。

来看看参数化SQL使用案例:

  /建立数据连接 
  conn=ds.getConnection(); 
  //1.设置prepareStatement带占位符的sql语句
   PreparedStatement ptmt = conn.prepareStatement("select * from user where userName = ? and password = ?");
   //2.设置参数  
   ptmt.setString(1, "张三"); 
   ptmt.setString(2, "123456"); 
   rs=ptmt.executeQuery(); 
   while(rs.next()){ 
       System.out.println("登陆成功"); 
       return; 
   } 
   System.out.println("登陆失败");

2、字符串过滤

比较通用的一个方法(||之间的参数可以根据自己程序的需要添加):

public static boolean sql_inj(String str) {
  String inj_str = "'|and|exec|insert|select|delete|update|
  count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+|,";
  String inj_stra[] = split(inj_str,"|");

  for (int i=0 ; i < inj_stra.length ; i++ ){
     if (str.indexOf(inj_stra[i])>=0){
        return true;
    }
  }
  return false;
}

3、框架技术

4、使用存储过程

posted @ 2021-12-20 17:55  习久性成  阅读(178)  评论(0编辑  收藏  举报