将SQL注入攻击阻止在发生之前[一]
注意,此文是西宁威势电子信息服务有限公司技术人员:孤行一鬼(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查询返回了相匹配的行数查询结果的数量。用户验证完成,并转向到了请求的页面。而哪些输入错误用户名和密码的用户将会验证失败。然而对于一个黑客来说,它可以输入一个其实并不存在,表面上看上去也无害的下面的字符,在不知道真正用户名和密码的情况下访问系统。
黑客通过注射一个畸形的查询到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'
但时当黑客输入
时,语句却变成了 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 – |
输入这个查询,显示了用户表中存在的USERNAME和PASSWORD,像下面显示的 FIGURE .3的示

Figure 3 Querying the Users Table
SQL注入攻击还可以被用来改变数据或损坏数据库。SQL注入的黑客可能输入下面的txtFilter 去改变第一个产品的价格从18美元到0.01美元,并且在别人察觉到他的行为之前,迅速的购买这些产品。 '; UPDATE Products SET UnitPrice = 0.01 WHERE ProductId = 1--
黑客能够得成是因为SQL SERVER充许你把多个SQL语句通过一个分号或空格连成一个。在这个例子中DataGrid什么也不显示,但是更新语句却正常的被执行了。利用相同的技术,可能被用来执行一条删除表的语句,或是执行一条系统存储扩展,用来创建一个用户,并加入系统管理员权限组中。这些黑客们都可能用例2中的BadProductList.aspx页面。
别给黑客机会
我们要了解SQL攻击不仅仅是局限在SQL SERVER上面,这一点很重要。其它的数据库,包括Oracle, MySQL, DB2, Sybase等都容易受到这种注入攻击。SQL注入攻击能够得逞是因为SQL语言包含强大的灵活性和有它的的一些特征:
连字符(--),在SQL中表示注释
能够把多语句拼起来执行
能够从标准配置的系统表中进行进数据查询
通常,数据库都支持一些更为有力的SQL查询语言,所以SQL SERVER数据库数据器经常被攻击,没必要大惊小怪的。
SQL 注入攻击不仅是发生在asp.net程序中,其它的如ASP ,JAVA,JSP和PHP中照样很容易引起攻击。实际上注入攻击。实际上,桌面程序也会受到SQL注入攻击,这一点上它并不见得能好到哪里去。举例,我已经在下载文件中打包了一个WINDOWS FORMS应用程序,名字为SQLINJECTWINFORM,它同样可以被SQL注入(在文章顶头的下载中可以下载到)
虽然可以很容易的指出一个或两个关键的SQL注入防范措施,可是最好我们还是采取分层的方式来解决。如果即便是你的一种方法因为漏洞被黑客绕过了,但是它还是守保护的。建议的总结层,如图4。
Principle |
Implementation |
永远不要相信用户的输入 |
验证用户所输入的字符,用验证控件,正则表达式,或代码等方式 |
永别使用动态构建语句 |
使用参数化 parameterized或是存储过程 stored procedures |
永远不要用ADMIN帐户去连数据库 |
最用低的权限去连接 |
不要把你的密码保存的TXT和其它文件中 |
密码信息和其它敏感信息都不要保存到一个文件中,另外还要对SQL连接字符串也要进行加密。 |
最少的出错提示信息 |
尽量使用自定义的错误信息,在出错时候不要显示太多的错误信息。将DEBUG设置为假 | |
所有的用户输入都是不可靠的
图4中的第一个原则是非常重要的,假设所有的用户输入都非常不可靠!你永远不要把用户的输入信息没有通过验证就带到数据库中进行查询。ASP.NET验证控件,特别是正则表达式验证控件是一个验证用户输入的好工具.有两种最简单的验证方式:禁止危险字符和允许所需要的字符.虽然你可以很EASY的禁止一些危险字符,如单引号和连字符,但是这样还不是最佳方法,有两个原因:第一,你可能在过滤时会漏掉一些对黑客很有用的字符,第二,通常,我们可以用多种方法来表示这个危险字符,来绕过过滤.比如黑客通过escaped一个单引号的方法绕过单引号限制,直接把它带到数据库中进行查询. Escaped的单引号在数据库中进行查询时,它和正常的单引号是没有任何区别的.这样就逃过了你的代码验证.更好的方法是只确实允许的字符.虽然这种方法加大了工作量,但是却保证了更好的安全性.除了上述的方法外,你还应该限定输入字符串的最大长度,因为黑客在攻击的时候,往往会需要输入大量的字符串.GoodLogin.aspx(在下载中可以找到)包含了两个正则表达式验证控件。一个是验证用户名的,另一个用来验证密码,让它限定在4-12个由字符、数字和下划限组成的字符串。 [\d_a-zA-Z]{4,12}
有时候我们可能需要让客户输入一些危险的过滤字符,举例, person’s name 中的单引号。这种情况下,你可以使用regular expression 或是 String.Replace 方法来将每个单引号替换成两个单引号。举例: string strSanitizedInput = strInput.Replace("'", "''");
注入测试
从测试的角度来看,我们重要的是要认识到,SQL注入的主要目标是企图通过改变被发送到SQL服务端查询的语句来控制SQL服务器。测试此漏洞前,你首先要知道如何利用这个漏洞,然后自己测试下面的方法:
寻找漏洞
黑客们开始在网站寻找漏洞。这些漏洞可能是任何可以接收输入,查找,提交表单,或是ASP,JSP,CGI或PHP页面,它们也包括隐藏域,而并不是局限在显示在页面上的域[译者加:域是指提交表单,输入框这类]
测试漏洞是否真的存在
为了测试漏洞是否可以成功利用,黑客们最常用的方法是单引号和撇号{apostrophe},[译者加:apostrophe翻译出来是撇的意思,其实应该是指分号";",因为分号可以将新的语句跟到前面的语句来执行,即多语句查询,以此为攻击。注,SQL SERVER支持多语句查询,ACCESS不支持]这两个字符是SQL语句中用来做分隔符之用。如果用户的输入没有通过验证而直接到达了数据库进行操作,那么搞定这个数据库管理系统将变得很简单。为了测试这样的漏洞,黑客们可能将 jo'hn 这样的代码输入到一个输入框中,或是输入到这样的一个地址中http://www.qhwins.com/index.asp?id=jo'hn 。 如果黑客利用的是代码中隐藏的一个域的话,这点小麻烦对黑客来说没算什么,它可以把源代码下载并保存下来,然后修改URL,隐藏字段,再去提交执行。
如果这是一个真正的弱点,撇号后的其他信息,将被视为一提交到SQL服务器的查询字符串的一部分,将由后端执行。
错误描述
如果黑客要找什么,哪么错误页对于黑客来说,将是帮助他们的一个很好的判断工具,因为错误页提供了黑客想要知道的一些信息。如果一个ODBC的错误信息被返回,黑客就确实了,这真的是一个可以利用的漏洞。这些错误是由数据库系统生成的,这也意味着单引号被成功带入到后台进行了查询。
继续测试
黑客们将继续尝试绕过网站的验证和其它过滤程序,认真的审查每条服务器的响应输出情况,这些努力包括:
改变单引号在不同的地方出现,试图在任何例程中有机可乘。例如,电子邮件域可能会验证一个@符号和一个句点。如果黑客输入joe'@qhwins.com ,这样将会验证失败,但是joe@qhwins.com' 将会成功,并发现漏洞。
在字符串最大长度的末尾上加一个单引号。如果网站转义了单引号,[原:If the site is escaping single quotes, an attempt to escape the single quote could result in truncation back to the single quote.]
使用连字符(破折号)。在SQL中,这意味后是单行注释,并可能导致服务器忽略该行的其余部份。
使用分号。这个表明后面跟的是一个新的查询,可以允许这个新查询在第一条语句后面被执行。
使用高级的unicode字符,它们经常被降级到ASCII “当量”,包括危险的单引号。[原:Using high Unicode characters that are often downgraded to ASCII "equivalents," including the dangerous single quote.]
在所有的字段域中使用这些技术,不光包括字符串域,而且包括任何隐式转换的地方和仅仅通过UI格式执行的域。
使用#字符。有时你会觉得这是一个日期/时间的分隔符使用。
使用等值的危险字符。 |
避免动态SQL
我在本文中演示的SQL注入攻击都是依赖在动态生成的SQL上执行的,即最终SQL语句是通过和用户输入的值进行相连接而成的。但是,使用参数化SQL,将会大大降低了黑客注入你代码的能力。在表5中的代码,员工employs的参数化SQL阻止了SQL注入的攻击。如果你必需使用ad hoc SQL(译者加:高级特性的SQL?是缩写,大家自己理解),参数化SQL将是很有用的。这可能是必要的,如果你的IT部门不相信存储过程或使用诸如MYSQL,MYSQL只至5.0才支持存储过程。无论如何,你应该使用存储过程来增加 删除所有基表权限和创建查询,像表3的示。BetterLogin.aspx,如表6所示,使用了一条存储过程,procVerifyUser来验证客户。[这段译的不太好,请自己看原文]
表6 BetterLogin.aspx.cs
private void cmdLogin_Click(object sender, System.EventArgs e) { string strCnx = ConfigurationSettings.AppSettings["cnxNWindBetter"]; using (SqlConnection cnx = new SqlConnection(strCnx)) { SqlParameter prm; cnx.Open(); string strAccessLevel; SqlCommand cmd = new SqlCommand("procVerifyUser", cnx); cmd.CommandType= CommandType.StoredProcedure; prm = new SqlParameter("@username",SqlDbType.VarChar,50); prm.Direction=ParameterDirection.Input; prm.Value = txtUser.Text; cmd.Parameters.Add(prm); prm = new SqlParameter("@password",SqlDbType.VarChar,50); prm.Direction=ParameterDirection.Input; prm.Value = txtPassword.Text; cmd.Parameters.Add(prm); strAccessLevel = (string) cmd.ExecuteScalar(); if (strAccessLevel.Length>0) { FormsAuthentication.RedirectFromLoginPage(txtUser.Text, false); } else { lblMsg.Text = "Login attempt failed."; } } } |
表 5 GoodLogin.aspx.cs
private void cmdLogin_Click(object sender, System.EventArgs e) { string strCnx = ConfigurationSettings.AppSettings["cnxNWindBad"]; using (SqlConnection cnx = new SqlConnection(strCnx)) { SqlParameter prm; cnx.Open(); string strQry = "SELECT Count(*) FROM Users WHERE UserName=@username " + "AND Password=@password"; int intRecs; SqlCommand cmd = new SqlCommand(strQry, cnx); cmd.CommandType= CommandType.Text; prm = new SqlParameter("@username",SqlDbType.VarChar,50); prm.Direction=ParameterDirection.Input; prm.Value = txtUser.Text; cmd.Parameters.Add(prm); prm = new SqlParameter("@password",SqlDbType.VarChar,50); prm.Direction=ParameterDirection.Input; prm.Value = txtPassword.Text; cmd.Parameters.Add(prm); intRecs = (int) cmd.ExecuteScalar(); if (intRecs>0) { FormsAuthentication.RedirectFromLoginPage(txtUser.Text, false); } else { lblMsg.Text = "Login attempt failed."; } } } |
用最小的权限执行
使用参数化SQL,大大降低了黑客注入你代码的能力,在Badlogin.aspx 和 BadProductList.aspx中有一个不好的做法就是连接字符串中使用了SA帐户。下面是连接字符串,你可以在WEB.CONFIG文件中找到它:
<add key="cnxNWindBad" value="server=localhost;uid=sa;pwd=;database=northwind;" /> |
此帐户运行于系统管理员的角色,这意思着它将会允许胡作非为,如创建一个登录,删除删除库这些操作都是小菜一碟。我只是想说明,数据库应用程序中用SA的方法是一个糟透了的做法。有一个更好的方法就是创建一个受限的用户来代替SA用户。GoodLogin.aspx中使用了下面的连接字符串:
<add key="cnxNWindGood" value="server=localhost;uid=NWindReader;pwd=utbbeesozg4d; database=northwind;" /> |
NWindReader帐户运行于db_datareader角色之下,这个角色被限定于只能读取数据库中的表。BetterLogin.aspx利用存储过程和一个登录改善了效率,WebLimitedUser只拥有执行该存储过程的权限,而无底层表的权利。
保存密码的安全
在表3所示的注入攻击中,导致USERS表中的用户名和密码显示出来。这类表经常被用在窗体身份验证中,并且许多程序中,用户名和密码以明文保存。一个更好的方法是把它们进行加密或哈希存储在数据库中。哈希密码比起加密密码更安全,因为他们不能被解密。你可以通过添加一个salt(盐?)(一个加密随机值)给哈希来强化一个哈希密码
BestLogin.aspx包含了把用户输入和存储在SecureUsers表(见表7)中被盐化(salted)哈希版本密码相比较的代码。哈希密的另一个是AddSecureUser.aspx页面。这个页面是用来得到被盐化的密码,把它们存到secureUsers表中。
表7 BestLogin.aspx.cs
private void cmdLogin_Click(object sender, System.EventArgs e) { try { // Grab the encrypted connection string and decrypt it string strCnx = SecureConnection.GetCnxString("cnxNWindBest"); // Establish connection to database using (SqlConnection cnx = new SqlConnection(strCnx)) { SqlParameter prm; cnx.Open(); // Execute sproc to retrieved hashed password for this user string strHashedDbPwd; SqlCommand cmd = new SqlCommand("procGetHashedPassword", cnx); cmd.CommandType = CommandType.StoredProcedure; prm = new SqlParameter("@username", SqlDbType.VarChar,50); prm.Direction = ParameterDirection.Input; prm.Value = txtUser.Text; cmd.Parameters.Add(prm); strHashedDbPwd = (string) cmd.ExecuteScalar(); if (strHashedDbPwd.Length>0) { // Verify that hashed user-entered password is the same // as the hashed password from the database if (SaltedHash.ValidatePassword(txtPassword.Text, strHashedDbPwd)) { FormsAuthentication.RedirectFromLoginPage( txtUser.Text, false); } else { lblMsg.Text = "Login attempt failed."; } } else { lblMsg.Text = "Login attempt failed."; } } } catch { lblMsg.Text = "Login attempt failed."; } } | BestLogin.aspx和AddSecureUser.aspx都使用了SaltedHash类库,如表8所示。这些代码都是使由JEFF PROSISE使用用
FormsAuthentication.HashPasswordForStoringInConfigFile方法来创建的,它继续于System.Web.Security 命名空间来创建密码哈希,和从
System.Security.Cryptography
这个命名空间RNGCryptoServiceProvider.GetNonZeroBytes方法来创建一个随机16位的盐化(salt value)值(使用Convert.ToBase64String将之转换为字符串时它将变成24位)
表 8 SaltedHash Class
using System; using System.Web.Security; using System.Security.Cryptography; public class SaltedHash { static public bool ValidatePassword (string password, string saltedHash) { // Extract hash and salt string const int LEN = 24; string saltString = saltedHash.Substring(saltedHash.Length - LEN); string hash1 = saltedHash.Substring(0, saltedHash.Length - LEN); // Append the salt string to the password string saltedPassword = password + saltString; // Hash the salted password string hash2 = FormsAuthentication.HashPasswordForStoringInConfigFile( saltedPassword, "SHA1"); // Compare the hashes return (hash1.CompareTo(hash2) == 0); } static public string CreateSaltedPasswordHash (string password) { // Generate random salt string RNGCryptoServiceProvider csp = new RNGCryptoServiceProvider(); byte[] saltBytes = new byte[16]; csp.GetNonZeroBytes(saltBytes); string saltString = Convert.ToBase64String(saltBytes); // Append the salt string to the password string saltedPassword = password + saltString; // Hash the salted password string hash = FormsAuthentication.HashPasswordForStoringInConfigFile( saltedPassword, "SHA1"); // Append the salt to the hash return hash + saltString; } } |
虽然没有直接关系到SQL注入攻击,但是BestLogin.aspx演示了另一个最安全的做法:加密连接字符串。
确保连接字符串安全是相当重要的,如果它包含了数据库帐户密码,做为一个例子看BestLogin.aspx。既然你需要解密连接字符串来连接数据库,所以你不能将它哈希加密,实际上你还需要解密。下面是存储在web.config中的加密后的连接字符串,在BestLogin.aspx页面中使用方法如下:
<add key="cnxNWindBest" value="AQAAANCMnd8BFdERjHoAwE/ Cl+sBAAAAcWMZ8XhPz0O8jHcS1539LAQAAAACAAAAAAADZgAAqAAAABAAAABdodw0YhWfcC6+ UjUUOiMwAAAAAASAAACgAAAAEAAAALPzjTRnAPt7/W8v38ikHL5IAAAAzctRyEcHxWkzxeqbq/ V9ogaSqS4UxvKC9zmrXUoJ9mwrNZ/ XZ9LgbfcDXIIAXm2DLRCGRHMtrZrp9yledz0n9kgP3b3s+ X8wFAAAANmLu0UfOJdTc4WjlQQgmZElY7Z8" /> | BestLogin calls the GetCnxString method from the SecureConnection class, shown in Figure 9, to retrieve the cnxNWindBest AppSetting value and decrypt it with this code:
BestLogin从SecureConnection类中调取GetCnxString方法,如表9所示,以此来检索和解密cnxNWindBest AppSetting的值。
string strCnx = SecureConnection.GetCnxString("cnxNWindBest"); public class SecureConnection { static public string GetCnxString(string configKey) { string strCnx; try { // Grab encrypted connection string from web.config string strEncryptedCnx = ConfigurationSettings.AppSettings[configKey]; // Decrypt the connection string DataProtector dp = new DataProtector(DataProtector.Store.USE_MACHINE_STORE); byte[] dataToDecrypt = Convert.FromBase64String(strEncryptedCnx); strCnx = Encoding.ASCII.GetString(dp.Decrypt(dataToDecrypt,null)); } catch { strCnx=""; } return strCnx; } }
|
SecureConnection类回调DataProtect类库(不在这里显示,但是可以在下载中找到)它封装调用了win32的数据保护API(DPAPI)。对DPAPI的很好特性之一就是它为您管理加密密钥。关于DataProtect类的更多信息,包括使用它的一些额外的选项,请参阅“构建安全的ASP.NET应用程序:身份验证,授权和安全通信”微软模式和实践指导。

表 10 EncryptCnxString.aspx
您可以使用EncryptCnxString.aspx页面创建计算机特有的加密连接字符串贴到你的配置文件中。这个页面显示所表10。当然,除了有连接字符串的密码和其他机密,您可能要加密或哈希,包括信用卡号码和其他任何可能造成损害的信息,否则他们可能会被泄露给黑客所知道。ASP.NET2.0包含了一些新特性,它简化了哈希密码和对连接字符串的加密。
优化错误信息
运行时的异常错误处理不当将成为被黑客利用的另一片领域。所以在你的代码产品中加入异常处理变得非常重要。处理的和未处理的异常信息应该提供最少的对黑客有利的信息。
此文首发于:http://www.qhwins.com/ShowNews/?11-200910271239038948.html 转载请注明出处
未完待续 :[原创]将SQL注入攻击阻止在发生之前[二]
|