第二章 相关技术研究
2.1 ASP.NET 动态网页及数据库连接技术
ASP.NET 的前身是 ASP 技术,指 Active Server Pages(动态服务器页面)。ASP.NET 是微软公司 2002 年推出的 Web 开发技术,是在 Windows 平台下的新型 Web 程序开发语言。经过几年的改进和优化,ASP.NET 已逐渐成为一种稳定而强大的 Web 开发语言。
(1) 面向对象性
ASP.NET 将 C#作为一种面向对象语言,在很多方面来看,C#将成为微软的与 Java 相似的语言。C#另一个有趣的地方是所有对象都自动变成为 COM 对象。C# 是 ASP.NET 开发中一个最重要的功能,微软将 C#发展成为 Java 的强劲对手,它可以和 Windows 环境紧密集成,C#产生的结果将进一步加固微软和 Sun 产品的战线。这对用户是有利的,他们可以选择两者之一来开发新的应用。
(2) 数据库连接
ASP.NET 另一个亮点是它使用 ADO 对象、ODBC、OLE-DB 和事务处理管理器。有了ADO.NET 带来了更强大更快速的功能,Web 数据库应用开发就特别简单,而且 ASP.NET 还发展了更多的功能。目前在易用性和性能上与 JSP 和 JDBC 相比具有一定的优势。
(3) 大型站点应用
ASP.NET 将对大型站点有更好的支持。事实上微软在这方面付出了巨大的努力。在考虑多服务器(Multiple Servers)的场合,当需要更强大的功能时,仅仅只需要增加一台服务器,整个。NET 框架已经充分地提供了这个方法。于是 ASP.NET 现在可以在大型项目方面与 JSP 一样具有等同的能力。而 ASP.NET 还有价格方面的优势,因为所有的组件将是服务器操作系统的一部分。对于 JSP 则需要购买昂贵的应用服务器群来达到同样的目的。
2.1.1 ADO.NET 访问数据库
ADO.NET 的名称起源于 ADO(ActiveX Data Objects),这是一个广泛的类组,用于在以往的 Microsoft 技术中访问数据。ADO.NET 是在 ADO 的基础上发展的新一代数据存取技术,是在。NET 开发环境中优先使用的数据访问接口。ADO.NET 提供了与对应数据交互的属性和方法,编程者可以通过这些属性和方法很方便地对各种数据源进行存取操作,例如 SQL 数据库、Access 数据库、Oracle 数据库和 XML 文件等。
在 ADO.NET 中,可以使用多种。NET Framework 数据提供程序来访问数据源。ADO.NET有 5 个主要的对象[4]:
(1) Connection:用于连接到数据库或其他数据源。
(2) Command:成功与数据建立连接后,就可以用 Command 对象来执行查询、修改、插入和删除等命令。
(3) DataReader:DataReader 对象允许开发人员获得从 Command 对象的 SELECT 语句得到的结果。从 DataReader 返回的数据都是快速的且只是“向前”的数据流,开发人员只能按照一定的顺序从数据流中取出数据。
(4) DataAdapter:用于将数据源中的数据填充到 DataSet 中,并将在 DataSet 中的数据更新后保存到数据库中。
(5) DataSet:数据集,是驻留在内存中的数据库,其中包含表、视图、表之间的关系等。
通常在无连接方式下使用 DataSet.
2.1.2 存储过程
存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的 SQL 语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象,任何一个设计良好的数据库应用程序都应该用到存储过程[5].
存储过程具有以下优点:
(1) 重复使用:存储过程可以重复使用,从而可以减少数据库开发人员的工作量。
(2) 提高性能:存储过程在创建的时候在进行了编译,将来使用的时候不再重新翻译。一般的 SQL 语句每执行一次就需要编译一次,所以使用存储过程提高了效率。
(3) 减少网络流量:存储过程位于服务器上,调用的时候只需要传递存储过程的名称以及参数就可以了,因此降低了网络传输的数据量。
(4) 安全性:假如将 SQL 语句混合在 ASP 代码中,一旦代码失密,同时也就意味着数据库结构失密。参数化的存储过程可以防止 SQL 注入式攻击,而且可以将 Grant、Deny 以及Revoke 权限应用于存储过程。
可用 CREATE PROCEDURE 语句创建存储过程,语法格式如下[5]:
CREATE PROC [EDURE] 存储过程名[;number]
[{@参数数据类型}
[VARYING][=默认值][OUTPUT]][,…n]
[WITH
{RECOMPILE|ENCRYPTION|RECOMPILE,ENCRYPTION}]
[FORREPLICATION]
AS sql 语句[…n]
参数说明:
(1) 存储过程名:新建存储过程名称必须符合标识符规则,且对于数据库及其所有者必须唯一。要创建局部临时过程,可以在存储过程名前面加一个编号符(#存储过程名),要创建全局临时过程,可以在存储过程名前面加两个编号符(##存储过程名)。
(2) number:是可选的整数,用来对同名的过程分组,以便用一条 DROP PROECDURE语句即可将同组的过程一起除去。
(3) @参数:过程中的参数。在 CREATE PROCEDURE 语句中可以声明一个或多个参数。数据类型用于限定参数的数据类型。
(4) OUTPUT:表名参数是否返回参数。该选项的值可以返回给 EXECUTE 语句。使用OUTPUT 参数可将信息返回给调用过程。
(5) RECOMPILE:表明 SQL Server 不会缓存该过程的计划,该过程将在运行时重新编译。
(6) ENCRYPTION:表示 SQL Server 加密 syscomments 表中包含 CREATE PROCEDURE语句文本的条目。
(7) FOR REPLICATION:不能在订阅服务器上执行为复制创建的存储过程。
2.2 MD5 算法研究
MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5的实现。对各种系统中的身份认证来说,“用户名+密码”的模式非常简单,很多编程人员为了将“密码”不明示,就对密码串进行MD5散列,在数据库或文件中保存MD5编码。
2.2.1 MD5 加密算法解析
在一些初始化处理后,MD5以512位分组来处理输入文本,每一分组又划分为16个32位子分组。算法的输出由四个32位分组组成,将它们级联形成一个128位散列值。首先填充消息使其长度恰好为一个比512位的倍数仅小64位的数。填充方法是附一个1在消息后面,接多个0,然后在其后附上64位的消息长度(填充前)。这两步的作用是使消息长度恰好是512位的整数倍(算法的其余部分要求如此),同时确保不同的消息在填充后不相同。
四个32位变量初始化为:
A=0x01234567
B=0x89abcdef
C=0xfedcba98
D=0x76543210
它们称为链接变量(chaining variable),接着进行算法的主循环,循环的次数是消息中512位消息分组的数目。将上面四个变量复制到别外的变量中:A到a,B到b,C到c,D到d.
主循环有四轮(MD4只有三轮),每轮很相拟。第一轮进行16次操作。每次操作对a,b,c和d中的其中三个作一次非线性函数运算,然后将所得结果加上第四个变量,文本的一个子分组和一个常数。再将所得结果向右循环移一个不定的数,并加上a,b,c或d中之一。最后用该结果取代a,b,c或d中之一。
以下是每次操作中用到的四个非线性函数(每轮一个)。
F(X,Y,Z)=(X&Y)|((~X)&Z)
G(X,Y,Z)=(X&Z)|(Y&(~Z))
H(X,Y,Z)=X^Y^Z
I(X,Y,Z)=Y^(X|(~Z))
这些函数是这样设计的:如果X、Y和Z的对应位是独立和均匀的,那么结果的每一位也应是独立和均匀的。函数F是按逐位方式操作:如果X,那么Y,否则Z.函数H是逐位奇偶操作符。
设Mj表示消息的第j个子分组(从0到15),<<< s表示循环左移s位,则四种操作为:
FF(a,b,c,d,Mj,s,ti)表示a=b+((a+(F(b,c,d)+Mj+ti)<<< s)
GG(a,b,c,d,Mj,s,ti)表示a=b+((a+(G(b,c,d)+Mj+ti)<<< s)
HH(a,b,c,d,Mj,s,ti)表示a=b+((a+(H(b,c,d)+Mj+ti)<<< s)
II(a,b,c,d,Mj,s,ti)表示a=b+((a+(I(b,c,d)+Mj+ti)<<< s)
这四轮(64步)是:
(1) 第一轮
FF(a,b,c,d,M0,7,0xd76aa478)
FF(d,a,b,c,M1,12,0xe8c7b756)
FF(c,d,a,b,M2,17,0x242070db)
FF(b,c,d,a,M3,22,0xc1bdceee)
FF(a,b,c,d,M4,7,0xf57c0faf)
FF(d,a,b,c,M5,12,0x4787c62a)
FF(c,d,a,b,M6,17,0xa8304613)
FF(b,c,d,a,M7,22,0xfd469501)
FF(a,b,c,d,M8,7,0x698098d8)
FF(d,a,b,c,M9,12,0x8b44f7af)
FF(c,d,a,b,M10,17,0xffff5bb1)
FF(b,c,d,a,M11,22,0x895cd7be)
FF(a,b,c,d,M12,7,0x6b901122)
FF(d,a,b,c,M13,12,0xfd987193)
FF(c,d,a,b,M14,17,0xa679438e)
FF(b,c,d,a,M15,22,0x49b40821)
(2) 第二轮
GG(a,b,c,d,M1,5,0xf61e2562)
GG(d,a,b,c,M6,9,0xc040b340)
GG(c,d,a,b,M11,14,0x265e5a51)
GG(b,c,d,a,M0,20,0xe9b6c7aa)
GG(a,b,c,d,M5,5,0xd62f105d)
GG(d,a,b,c,M10,9,0×02441453)
GG(c,d,a,b,M15,14,0xd8a1e681)
GG(b,c,d,a,M4,20,0xe7d3fbc8)
GG(a,b,c,d,M9,5,0x21e1cde6)
GG(d,a,b,c,M14,9,0xc33707d6)
GG(c,d,a,b,M3,14,0xf4d50d87)
GG(b,c,d,a,M8,20,0x455a14ed)
GG(a,b,c,d,M13,5,0xa9e3e905)
GG(d,a,b,c,M2,9,0xfcefa3f8)
GG(c,d,a,b,M7,14,0x676f02d9)
GG(b,c,d,a,M12,20,0x8d2a4c8a)
(3) 第三轮
HH(a,b,c,d,M5,4,0xfffa3942)
HH(d,a,b,c,M8,11,0x8771f681)
HH(c,d,a,b,M11,16,0x6d9d6122)
HH(b,c,d,a,M14,23,0xfde5380c)
HH(a,b,c,d,M1,4,0xa4beea44)
HH(d,a,b,c,M4,11,0x4bdecfa9)
HH(c,d,a,b,M7,16,0xf6bb4b60)
HH(b,c,d,a,M10,23,0xbebfbc70)
HH(a,b,c,d,M13,4,0x289b7ec6)
HH(d,a,b,c,M0,11,0xeaa127fa)
HH(c,d,a,b,M3,16,0xd4ef3085)
HH(b,c,d,a,M6,23,0x04881d05)
HH(a,b,c,d,M9,4,0xd9d4d039)
HH(d,a,b,c,M12,11,0xe6db99e5)
HH(c,d,a,b,M15,16,0x1fa27cf8)
HH(b,c,d,a,M2,23,0xc4ac5665)
(4) 第四轮
II(a,b,c,d,M0,6,0xf4292244)
II(d,a,b,c,M7,10,0x432aff97)
II(c,d,a,b,M14,15,0xab9423a7)
II(b,c,d,a,M5,21,0xfc93a039)
II(a,b,c,d,M12,6,0x655b59c3)
II(d,a,b,c,M3,10,0x8f0ccc92)
II(c,d,a,b,M10,15,0xffeff47d)
II(b,c,d,a,M1,21,0x85845dd1)
II(a,b,c,d,M8,6,0x6fa87e4f)
II(d,a,b,c,M15,10,0xfe2ce6e0)
II(c,d,a,b,M6,15,0xa3014314)
II(b,c,d,a,M13,21,0x4e0811a1)
II(a,b,c,d,M4,6,0xf7537e82)
II(d,a,b,c,M11,10,0xbd3af235)
II(c,d,a,b,M2,15,0x2ad7d2bb) II(b,c,d,a,M9,21,0xeb86d391)
常数ti可以如下选择:在第i步中,ti是4294967296*abs(sin(i))的整数部分,i的单位是弧度。(2的32次方)所有这些完成之后,将A,B,C,D分别加上a,b,c,d.然后用下一分组数据继续运行算法,最后的输出是A,B,C和D的级联。[6]在。NET环境下对密码进行32位MD5编码,最简单的实现方法:System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(“要编码的字符串”, “MD5”)[7].
2.2.2 使用 MD5 变换算法来防止穷举破译密码
回顾使用MD5加密文本密码的初衷,就是为了防止数据库中保存的密码不幸泄露后被直接获得。但攻击者不但拥有数据量巨大的密码字典,而且建立了很多MD5原文和密文对照数据库,能快速地找到常用密码的MD5密文,是破译MD5密文的高效途径。然而,MD5密文数据库所使用的是最常规的MD5加密算法。因此,我们可以使用变换的MD5算法,使现成的MD5密文数据库无所作为。
(1) 变换一:循环MD5
最容易理解的变换就是对一个密码进行多次的MD5运算。自定义一个函数,它接受两个形参,第一个形参是要加密的密码,第二个形参是重复加密的次数。
(2) 变换二:密文分割MD5
尽管用户的密码是不确定的字符串,但是只要经过一次MD5运算后,就会得到一个由32个字符组成的字符串,这时可以再针对这个定长字符串变换。还可以把这段密文分割成若干段,对每段都进行一次MD5运算,然后把这堆密文连成一个超长的字符串,最后再进行一次MD5运算,得到仍然是长度为32位的密文。当然,这种密文分割的具体算法是数之不尽的,比如可以把原密文分割成16段每段两字符、8段每段4字符,或者每一段的字符数不相等……
(3) 变换三:附加字符串干涉
在加密过程的一个步骤中,附加一个内容确定的字符串(比如说用户名),干涉被加密的数据。不可以用随机字串,因为这样会使原算法无法重现。这种算法在某些情况下是很具有优势的,比如说用于大量的用户密码加密,可以把用户名作为附加干涉字串,这样攻击者就算知道你的算法,也很难从他们手中的字典中一下子生成海量的对照表,然后大量地破译用户密码,只能有针对性的穷举为数不多的用户。
(4) 变换四:大小写变换干涉
由于一些软件开发工具中MD5函数返回的密文英文字母全部都是小写,因此我们可以把它们全部转为大写,然后再进行一次MD5运算。
(5) 变换五:字符串次序干涉
把MD5运算后的密文字符串的顺序调转后,再进行一次MD5运算。
MD5变换算法是数之不尽的,甚至无须自己再去创造,就用上面的五个互相组合就可以了。比如说先循环加密后再分割,并在每一段上附加一个字符串再分别加密,然后变换大小写并颠倒字符串顺序后连成一个长字符串再进行MD5运算。本课题中选择的MD5变换算法是第一种变换算法。