注意,此文是西宁威势电子信息服务有限公司技术人员:孤行一鬼(QQ:147399120)翻译英文技术文献而来,原文章版权归原作者所有,此译文版权归西宁威势电子信息服务有限公司 以及译者所有。原文出处为微软官方网站,此段说明文字是本文章不可缺少的一部分,此文首发于西宁威势电子公司网站,您可以自由转载,但请保持文章的完整性,并注明出处,否则西宁威势电子信息服务有限公司有权力追究版权责任。
译者的话:
近年来SQL注入攻击大行其道,好多大型站点和很多服务器被都这些攻击放倒了,老鬼本人也对注入攻击有一些肤浅的了解,但是水平和那些国内外的顶尖大牛们相比还相差甚远,本来以老鬼的水平是没有资格发布这样的文章的,因为老鬼不是专搞安全的,更不是学英语的,一方面技术有限,对原作者的思路理解可能不是很到位,另一方面E文忒菜,翻译的时候难免会出错,而发布这篇文章的主要原因是,老鬼加入了好多技术交流群,好多群内写程序写了四五年的编程人员,对自己网站的安全没有一点概念,好多人经常在群里发问:“我看到我的服务器日志中,有人经常扫描我的SQL端口和密码,我的服务器是不是离挂不远了?”、“我的数据库要是放到内网以防黑客攻击,而WEB服务器在外网,这样我的网站还能打开吗?还能正常使用吗?”由此看来,更多的人对网络安全是一无所知的,所以老鬼斗胆把以前翻译的一篇安全文章贴出来,一方面是引导新人,另一方面我是关老爷门前耍大刀,让高手们指点指点,起个抛砖引玉的作用,以提高我个人对安全方面认识的不足。By the way,我发布这样的文章,并不代表我的站点亦很安全,请大牛们友情测试我的站点的时候手下留情,点到为止,并将BUG来信告之(147399120@qq.com),我更欢大牛们直接加我QQ进行指点和斧正。在翻译过程中,老鬼对有些拿捏不准的语句,在“[ ]”中给出了原语句,如果翻译不对,大家请对照原语句理解。
译文开始:
数据安全
《将SQL注入阻止在发生之前》
这篇文章介绍了:
如何SQL注入攻击网络
测试SQL注入的漏洞
验证用户的输入
使用.NET特性来阻止攻击
程序异常处理的重要性
文章提到以下知识
ASP。NET C#,SQL
[示例代码下载] SQLInjection.exe (153 KB)
内容提纲
好好的SQL语句发生了问题
不给黑客机会 [原:Equal Opportunity Hacks]
所有的输入都很不安全
避免动态的SQL
用最小的权限执行
优化错误信息[原:Failing Gracefully]
结论
开发者们有了诸如ASP.NET 和强大的数据库服务,如Microsoft® SQL Server™的先进的服务端技术武装以后,他们可以很轻松开发出动态的,数据库驱动的WEB站点.但是功能强大的ASP.NET 和 SQL 却能够被黑客通过架设一个“所有通用”[原: all-too-common ]类的攻击,那就是―――SQL注入攻击。
最简单的攻击思路是这样的:你创建了一个WEB页,这个页允许用户在输入框中输入字符,这个字符可以被引入到数据库中去经理查询操作。一个黑客在这个输入框中输入了一个畸形SQL 语句,从而改变了原有的查询,用是它可以被用来插入,改变,或损害后台数据库。这怎么可能呢?让我来举个例子吧。
好语句也不好使了
许多ASP.NET程序都使用和下面“代码段一”一样的方法来进行用户身份验证。
当用户单击了BadLogin.aspx的登录按钮时,cmdLogin_Click 方法就会通过运行一个查询去计算记录集的数量值,记录集是在用户表 Users table 中进行匹配,条件是用户名字段UserName和密码字段Password要和用户输入的一致,以此来尝试验证这个用户。
Figure 1 BadLogin.aspx.cs
以下是引用片段: private void cmdLogin_Click(object sender, System.EventArgs e) { string strCnx = "server=localhost;database=northwind;uid=sa;pwd=;"; SqlConnection cnx = new SqlConnection(strCnx);
cnx.Open();
//This code is susceptible to SQL injection attacks. string strQry = "SELECT Count(*) FROM Users WHERE UserName='" + txtUser.Text + "' AND Password='" + txtPassword.Text + "'"; int intRecs;
SqlCommand cmd = new SqlCommand(strQry, cnx); intRecs = (int) cmd.ExecuteScalar();
if (intRecs>0) { FormsAuthentication.RedirectFromLoginPage(txtUser.Text, false); } else { lblMsg.Text = "Login attempt failed."; }
cnx.Close(); } |
在多数情况下,程序都会按我们意想的工作。用户输入一个用户名和密码,然后在USER表中进行比较。此时一个动态的SQL查询返回了相匹配的行数查询结果的数量。用户验证完成,并转向到了请求的页面。而哪些输入错误用户名和密码的用户将会验证失败。然而对于一个黑客来说,它可以输入一个其实并不存在,表面上看上去也无害的下面的字符,在不知道真正用户名和密码的情况下访问系统。
以下是引用片段: ' Or 1=1 -- |
黑客通过注射一个畸形的查询到SQL语句中从而中断了系统。这样之所以能运行是因为给输入的user连接了一个固定的字符串和值,看下面所示:[翻译不准,看原文This particular hack works because the executed query is formed by the concatenation of a fixed string and values entered by the user, as shown here:]
以下是引用片段: string strQry = "SELECT Count(*) FROM Users WHERE UserName='" + txtUser.Text + "' AND Password='" + txtPassword.Text + "'"; |
当用户输入一个无效的用户名‘Paul’ 密码 ‘Password’ 的时候,strQry变量成为
SELECT Count(*) FROM Users WHERE UserName='Paul' AND Password='password'
但时当黑客输入
以下是引用片段: ' Or 1=1 -- |
时,语句却变成了
SELECT Count(*) FROM Users WHERE UserName='' Or 1=1 --' AND Password=''
因为两个” --” 符号指定了开始查询的SQL语句,查询条件变成:
SELECT Count(*) FROM Users WHERE UserName='' Or 1=1
(这里译得可能不太准,给出源文Because a pair of hyphens designate the beginning of a comment in SQL, the query becomes simply:)
[译者加:两个连字符――后面的内容被当做注释内容被系统忽略了,所以“――”后面的语句等同于无效]
表达式1=1是恒成立的,而这个条件为真的值与任何表达式OR运算,返回结果永远是真,所以最少有一行返回记录可以保证,这条查询经常会返回一个非零的记录集。
不是所有的SQL 注入攻击都包括验证注入的(翻译不太好,译者加:也就是说其它情况也会有注入)[原:Not all SQL injection attacks involve forms authentication],一些动态的构造SQL语句和未验证的输入都会让攻击发生。给出正确的危害发生的限定情况,范围,或许可以一个攻击限定到黑客仅有的SQL语言知识或是数据库情况。
现在我们再考虑“代码段二”取自于BadProductList.aspx.这个页面从NORTHWIND DATABASE[译者加:装完SQL2000后会自带这个数据库] 中显示产品,并且允许用户通过一个名为textFilter的textbox来过滤输出结果。如最后的这个例子,这个页面可以成功的被SQL注入攻击,因为执行语句是由用户输入的值来动态构建而成的。这个特殊的页面就成了电脑黑客的天堂,是因为他可以让这个机敏的黑客劫持机密数据,改变数据库的的数据,损害数据库记录,甚至创建一个新的数据库帐户。
代码段 2 BadProductList.aspx.cs
以下是引用片段: private void cmdFilter_Click(object sender, System.EventArgs e) { dgrProducts.CurrentPageIndex = 0; bindDataGrid(); } private void bindDataGrid() { dgrProducts.DataSource = createDataView(); dgrProducts.DataBind(); } private DataView createDataView() { string strCnx = "server=localhost;uid=sa;pwd=;database=northwind;"; string strSQL = "SELECT ProductId, ProductName, " + "QuantityPerUnit, UnitPrice FROM Products"; //This code is susceptible to SQL injection attacks. if (txtFilter.Text.Length > 0) { strSQL += " WHERE ProductName LIKE '" + txtFilter.Text + "'"; } SqlConnection cnx = new SqlConnection(strCnx); SqlDataAdapter sda = new SqlDataAdapter(strSQL, cnx); DataTable dtProducts = new DataTable(); sda.Fill(dtProducts); return dtProducts.DefaultView; } |
许多SQL-compliant 数据库,包括SQL SERVER,保存metadata 到一系列的系统表中,有着这样的名字 sysobjects,syscolumns,sysindexes等。这意味着黑客们通过使用这些系统表来进一步获得数据库的大概信息。如,下面的字输入到texFilter的 textbox中,可能会显示数据库中的用户表
以下是引用片段: ' UNION SELECT id, name, '', 0 FROM sysobjects WHERE xtype ='U' -- |
UNION查询语句对黑客来说是非常有用的,因为它可以把一个查询语句附合到另一个查询语句上去。在这个例子中,黑客把数据库中的表名附加到最初的产品查询表上。只有一点不好的是要计算原查询列的数量和数据类型。最先的查询可能会显示一个命名为数据库中用户存在的表。第二次的查询能够显示用户表中的列。用这些信息,黑客可能输入下面的字符到testbox中:
以下是引用片段: ' UNION SELECT 0, UserName, Password, 0 FROM Users – |