原文地址:http://www.cnblogs.com/rush/archive/2011/12/31/2309203.html
1.1.1 总结
前几天,国内最大的程序猿社区CSDN网站的用户数据库的黑客公告,600登录名和万用户password被公开泄露,随后又有多家站点的用户password被流传于网络。连日来引发众多网民对自己账号、password等互联网信息被盗取的普遍担忧。
网络安全成为了如今互联网的焦点。这也恰恰触动了每一位用户的神经,因为设计的漏洞导致了不可收拾的恶果,验证了一句话“出来混的,迟早是要还的”,所以我想通过专题博文介绍一些经常使用的攻击技术和防范策略。
SQL Injection或许非常多人都知道或者使用过。假设没有了解或全然没有听过也没有关系,由于接下来我们将介绍SQL Injection。
1.1.2 正文
SQL Injection:就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,终于达到欺骗server运行恶意的SQL命令。
详细来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎运行的能力。它能够通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的站点上的数据库。而不是依照设计者意图去运行SQL语句。
首先让我们了解什么时候可能发生SQL Injection。
如果我们在浏览器中输入URL 。因为它仅仅是对页面的简单请求无需对数据库动进行动态请求。所以它不存在SQL Injection。当我们输入
testid=23时,我们在URL中传递变量testid,而且提供值为23,因为它是对数据库进行动态查询的请求(当中?testid=23表示数据库查询变量),所以我们能够该URL中嵌入恶意SQL语句。
如今我们知道SQL Injection适用场合,接下来我们将通过详细的样例来说明SQL Injection的应用。这里我们以数据库作为样例。
我们通过Web页面查询job表中的招聘信息。job表的设计例如以下:
图1 jobs表
接着让我们实现Web程序,它依据工作Id(job_id)来查询对应的招聘信息,示意代码例如以下:
////// Handles the Load event of the Page control./// /// The source of the event./// Theinstance containing the event data.protected void Page_Load(object sender, EventArgs e){ if (!IsPostBack) { // Gets departmentId from http request. string queryString = Request.QueryString["departmentID"]; if (!string.IsNullOrEmpty(queryString)) { // Gets data from database. gdvData.DataSource = GetData(queryString.Trim()); // Binds data to gridview. gdvData.DataBind(); } }}
如今我们已经完毕了Web程序。接下来让我们查询对应招聘信息吧。
图2 job表查询结果
如图所看到的,我们要查询数据库中工作Id值为1的工作信息,并且在页面显示了该工作的Id,Description。Min Lvl和Max Lvl等信息。
如今要求我们实现依据工作Id查询对应工作信息的功能,想必大家非常快能够给出解决方式。SQL示意代码例如以下:
SELECT job_id, job_desc, min_lvl, max_lvlFROM jobsWHERE (job_id = 1)
如果如今要求我们获取Department表中的全部数据,并且必须保留WHERE语句。那我们仅仅要确保WHERE恒真就OK了,SQL示意代码例如以下:
SELECT job_id, job_desc, min_lvl, max_lvlFROM jobsWHERE (job_id = 1) OR 1 = 1
上面我们使得WHERE恒真,所以该查询中WHERE已经不起作用了,其查询结果等同于下面SQL语句。
SELECT job_id, job_desc, min_lvl, max_lvlFROM jobs
SQL查询代码实现例如以下:
string sql1 = string.Format( "SELECT job_id, job_desc, min_lvl, max_lvl FROM jobs WHERE job_id='{0}'", jobId);
如今我们要通过页面请求的方式,让数据库运行我们的SQL语句,我们要在URL中嵌入恶意表达式1=1(或2=2等等)。例如以下URL所看到的:
图3 job表查询结果
如今我们把job表中的全部数据都查询出来了,只通过一个简单的恒真表达式就能够进行了一次简单的攻击。
尽管我们把job表的数据都查询出来了,但数据并没有太大的价值,因为我们把该表暂时命名为job表,所以接着我们要找出该表真正表名。
首先我们如果表名就是job。然后输入下面URL:
jobid=1'or 1=(select count(*) from job)--
等效SQL语句例如以下:
SELECT job_id, job_desc, min_lvl, max_lvl FROM jobs WHERE job_id='1'or 1=(select count(*) from job) --'
图4 job表查询结果
当我们输入了以上URL后,结果server返回我们错误信息,这证明了我们的如果是错误的,那我们该感觉到挫败吗?不,事实上这里返回了非常多信息,首先它证明了该表名不是job,并且它还告诉我们后台数据库是SQL Server,不是MySQL或Oracle,这也设计一个漏洞把错误信息直接返回给了用户。
接下假定表名是jobs,然后输入下面URL:
等效SQL语句例如以下:
SELECT job_id, job_desc, min_lvl, max_lvl FROM jobs WHERE job_id='1'or 1=(select count(*) from jobs) --'
图5 job表查询结果
如今证明了该表名是jobs,这能够迈向成功的一大步,因为我们知道了表名就能够对该表进行增删改操作了。并且我们还能够推測出很多其它的表对它们作出改动,一旦改动成功那么这将是一场灾难。
如今大家已经对SQL Injection的攻击有了初步的了解了,接下让我们学习怎样防止SQL Injection。
总的来说有下面几点:
1.永远不要信任用户的输入。要对用户的输入进行校验,能够通过正則表達式,或限制长度。对单引號和双"-"进行转换等。
2.永远不要使用动态拼装SQL,能够使用參数化的SQL或者直接使用存储过程进行数据查询存取。
3.永远不要使用管理员权限的数据库连接。为每一个应用使用单独的权限有限的数据库连接。
4.不要把机密信息明文存放,请加密或者hash掉password和敏感的信息。
5.应用的异常信息应该给出尽可能少的提示,最好使用自己定义的错误信息对原始错误信息进行包装,把异常信息存放在独立的表中。
通过正则表达校验用户输入
首先我们能够通过正則表達式校验用户输入数据中是包括:对单引號和双"-"进行转换等字符。
然后继续校验输入数据中是否包括SQL语句的保留字,如:WHERE,EXEC。DROP等。
如今让我们编写正則表達式来校验用户的输入吧。正則表達式定义例如以下:
private static readonly Regex RegSystemThreats = new Regex(@"\s?or\s*|\s?
;\s?|\s?
drop\s|\s?
grant\s|^'|\s?
--|\s?union\s|\s?delete\s|\s?
truncate\s|"
+ @"\s?sysobjects\s?|\s?xp_.*?|\s?syslogins\s?|\s?sysremote\s?|\s?sysusers\s?|\s?sysxlogins\s?|\s?sysdatabases\s?|\s?
aspnet_.*?
|\s?exec\s?
"
, RegexOptions.Compiled | RegexOptions.IgnoreCase);上面我们定义了一个正則表達式对象RegSystemThreats,而且给它传递了校验用户输入的正則表達式。
因为我们已经完毕了对用户输入校验的正則表達式了,接下来就是通过该正則表達式来校验用户输入是否合法了,因为.NET已经帮我们实现了推断字符串是否匹配正則表達式的方法——IsMatch()。所以我们这里仅仅需给传递要匹配的字符串就OK了。
示意代码例如以下:
////// A helper method to attempt to discover [known] SqlInjection attacks. /// /// string of the whereClause to check///true if found, false if not found public static bool DetectSqlInjection(string whereClause){ return RegSystemThreats.IsMatch(whereClause);}////// A helper method to attempt to discover [known] SqlInjection attacks. /// /// string of the whereClause to check/// string of the orderBy clause to check///true if found, false if not found public static bool DetectSqlInjection(string whereClause, string orderBy){ return RegSystemThreats.IsMatch(whereClause) || RegSystemThreats.IsMatch(orderBy);}
如今我们完毕了校验用的正則表達式。接下来让我们须要在页面中加入校验功能。
////// Handles the Load event of the Page control./// /// The source of the event./// Theinstance containing the event data.protected void Page_Load(object sender, EventArgs e){ if (!IsPostBack) { // Gets departmentId from http request. string queryString = Request.QueryString["jobId"]; if (!string.IsNullOrEmpty(queryString)) { if (!DetectSqlInjection(queryString) && !DetectSqlInjection(queryString, queryString)) { // Gets data from database. gdvData.DataSource = GetData(queryString.Trim()); // Binds data to gridview. gdvData.DataBind(); } else { throw new Exception("Please enter correct field"); } } }}
当我们再次运行下面URL时,被嵌入的恶意语句被校验出来了。从而在一定程度上防止了SQL Injection。