使用Windows NT 的 安全 性: 在上一节,我们已经阐述了推荐使用Windows NT做Web服务器的一些理由,其最重要的一点是,能够使用Windows NT的 安全 性API。然而,懂得为什么要存在Windows NT的 安全 性API只是一个起步,现在,我们将要关注的是,在现实中你是如何实施这些 安全 特性的。在这一章中,我们实际上讲述了五种不同类型或等级的 安全 特性,下面将对每种类型进行定义:
注 使用Windows NT作为Internet服务器的一个主要原因是,你能使用它的 安全 性API。
内置 安全 性 作为一个操作系统,Windows NT有一定级别的 安全 性。在Windows NT中,每个对象都对应着一定的 安全 性,我们将关注这些 安全 性的实施方法。使用对象级别的 安全 性意味着:如果没有正确的授权,几乎没人能有机会访问操作系统的任何部分或任何数据,当然,也不是一点机会也没有——我们总是假设你的 安全 性不是最完美的。
私有通讯技术(PCT) PCT是微软和IETF一起创建的一种特殊的Internet 安全 性技术。在近期版本中,PCT将允许客户和服务器建立私有的通讯,以保证通讯不会被人窃听到,这种 安全 性的实现依赖于数字签名和加密方法。
Windows NT通过HTTP进行身份认证 许多人都错误地认为,使用这些 安全 性来工作将是非常繁琐和复杂的,但有时候,看似烦杂的东西却可以通过一个简单的方案做到尽善尽美。我们从Internet的角度来看,在Windows NT中进行身份认证有两种形式,一种形式是简单地询问用户的用户名和口令,并和服务器内的访问列表进行对照,这种形式又可通过两种方法实现,一种是在对Windows NT进行标准登录时进行的询问和回答;另一种则基于当前会话的设置,它也要求客户提供必要的用户名和口令,或者说,让用户使用客户提供的信息登录到机器上。另一种形式相对简单些,它依赖于一种叫 安全 套接层(SSL)的技术,SSL又是依靠加密和数字认证来工作的。如果你过于担心 安全 性问题,你甚至可以将这两种形式结合起来使用——它们彼此间并没有什么相互的制约关系。
数字签名 它是指发送人对他发送的文档或可执行文件进行签名,通过检测签名你可以判断其真伪。数字签名用一系列的私有或公开密钥来实现这个 安全 等级。
加密API 有些类型的 安全 性依靠多个保护层来工作,也就是说,如果一个 黑客 闯过了你的第一个 安全 保护层,则另一个保护层将阻止他进一步的访问。这就是加密API(也叫CryptoAPI)所有要做的,它是一个附加的保护层,附加在所有已经存在的保护层上,它能保护你免受 黑客 更深层次的攻击。
在本章的下几节中,我们将阅读到几种新的技术,你将发现它既嵌入在Windows NT中,也嵌入在新型的浏览器中。作为Internet服务器中的一种,Windows NT支持如微软的Internet信息服务或对等网信息服务(在WindowsNT4.0和Windows95/98的OSR2版本中免费提供)。我们将有趣地发现:和新版本的Netscape转接器一样,微软的IE3.x/4.x中也提供了内置SSL的支持;你也将发现,PCT至少也支持IE。我们也将关注数字认证码(即数字签名)技术,现在的许多软件厂家已经采用了它,它允许编程人员对其作品进行数字化签名,当你下载这些经过数字化签名的程序时,程序代码在签名后的任何损坏都将显示出来。它带来的好处是,你不会轻易下载到一个病毒感染过的程序。
Web链接 通过访问http://www.microsoft.com/iis/guide/pws.asp?A=2&B=5,你可以为你的Windows 95下载某个版本的个人Web服务器(PWS,Person WebServer)(Windows 98的安装包中自带了PWS),这个版本的PWS也与Windows 95的OSR2版本以及微软的Windows NT可选包随同销售(Windows 95/98也有其可选包)。虽然PWS不会去满足制造Web站点的需求,但它能够让开发者很好地检测Internet 应用程序。要知道,因为Windows 95/98没有提供与Windows NT一样的 安全 性,所以,如果使用Windows95/98的PWS版本,你将检测不到应用程序的任何 安全 特性。(幸运的是,在与Windows NT 4.0 Workstation一同销售的PWS中,将允许你完全检测这些 安全 特性)。
加密也是保护你的数据的另一个可行方法,让我们参看一下下述微软已经开发的加密函数CryptoAPI,这部分的技术至少是在Internet Explorer内的一种主要形式。然而,不管你现在能够使用它做什么工作,CryptoAPI确实在程序内工作着,另外,对CryptoAPI的开发环境进行扩展,只在美国和加拿大是有效的。
内置的安全特性 
在 安全 性方面,Windows NT几乎是当前市场上最超前的操作系统。如果你对微软的这种地位还有什么怀疑的话,那么请去看看Windows NT获得的各种证书吧。你可以通过使用它的 安全 性能来获取很多便利,例如,你可以在一个OCX中使用这些高级功能,或通过Internet获得一些特殊功能的访问。在做这些事时,你必须受到一些限制,以免破坏你的网络 安全 。使用一些来自Internet的特性是不切实际的,因为它们并不重要。
幸运的是,ActiveX控件却不必对Internet进行限制,没有什么条令规定,你不能在你的应用程序中创建一个有特殊用途的控件。在数据库或其它应用程序中的ActiveX控件,能被网络管理员(或其他有相同权利的人)正常地使用,这使应用程序的工作变得更加简单和可靠。事实上,如果你需要的话,ActiveX控件也可以设计为多种个性化用途,你甚至可以给它增加检测控件当前位置的能力,或增加一个指定的位置作为特性页面配置的一部分,一些人可以选择其用于Internet的特性子集,而另外一些人则可以选择其用于局域网(LAN)的特性子集,还有一些特性集则是用于本地的。
也许你们中许多人会问:需要什么类型的管理员来管理 安全 性,且不需使用网络操作系统(NOS)附加的 工具 呢?Windows NT确实提供了大量的管理 工具 ,而且这些 工具 都非常容易使用,所以一些编程者认为,再附加一些 工具 是不值得的。这个问题不好回答,但是,当大部分人在考虑Window NT下的 安全 性时,几乎总是这么想:如果管理应用程序的人不是网络管理员,而是练习使用网络操作系统的某个人,这又该如何处理呢?我们说这个人可能是一个工作组管理员或其他独立的个体,他没有必要看到整个网络图,而只需要足够的信息来维护他所负责的应用程序,你将发现这种情况是经常发生的,尤其是一个拥有许多小工作组的大公司,更是属于此类情况。尽管网络管理员不懂得正确管理应用程序,但也不愿让工作组管理员自由地访问整个网络。
注 ActiveX在局域网环境的一个最好的应用是,它提供一定的子网 安全 管理能力。
不管你是在为Internet、还是为局域网(LAN)或是为广域网(WAN)创建控件,你都将发现,懂得网络底层的 安全 构造是非常重要的。Windows 95/98没有提供像Windows NT一样多的 安全 特性,所以,在Windows 95/98 中,你有时会发现自己没有增加上应用程序的 安全 性。然而,尽管Windows 95/98没有为应用程序提供某个 安全 特性,但有时它们和Windows NT使用同样的安装程序,所以应用程序 安全 模块将同时为这两种操作系统工作(在其它情形下,你可以干脆为Windows NT使用单独的 安全 模块,以增强其 安全 性能,请看下面的具体注释)。
注释 与Windows 95/98相比,Windows NT确实提供了更多的 安全 API函数,因为它的 安全 性更加强壮。现实中,因为Windows 95/98缺少对Windows NT 安全 函数的支持,所以在使用它时,你会经常遇到一些障碍。例如,在Windows 95/98下,你不能调用GetUserObjectSecurity函数;而在下一节中,我们将会看到的操作访问令牌的函数,也大多不能在Windows 95/98中使用。弄清一个函数是否被支持的最好方法就是直接检测它,如果你在调用它时收到一个“ERROR_CALL_NOT_IMPLEMENTED(value 120)”的信息,则你便知道它只能在Windows NT中使用了。
在Windows NT 和Windows 95/98中,“对象”(Object)这一名词的使用更加宽松。我们说,在事物的背后确实潜伏着许多对象,但你可能发现,“对象”这个名词的定义已经不能完全符合C++的习俗了。在下几节中,我们把对象大体看成是:在运行一个指定的 安全 任务时所需的代码和数据的总和。或者说,每个 安全 对象自身包含了一个为充当某个角色而设计的单元。(在WindowsNT和Windows 95/98的许多地方,微软主要选用C++中“对象”的定义,因为作为MFC的一部分,它提供了所需的机能。然而,在阅读本章或微软的其它文档时,你不应该把对象看成是一个严格的C++对象,而应该多加点COM的意识)。
知道了所有东西都是对象后,我们将更容易理解 安全 性——这至少是一个起点,当然,对象本身也就是一个起点。对象是被用户所访问的,所以在Windows中, 安全 性是指将对象所受的保护与用户的访问权进行比较。如果用户拥有足够的访问权(访问权等于或超过对象所受的保护),则用户能够使用这个对象。在Windows 的文档中将对象所受保护的级别称作 安全 描述符(securitydescriptor),这是一种结构,它能告诉 安全 系统:用户需要什么样的权力才能访问这个对象;而用户则有一个访问令牌(Access Token),它是另一种结构,它能告诉 安全 系统:在一个给定的位置,用户有什么样的访问权。用户将访问令牌交给Windows NT系统,并以此获得对对象的访问。(如果把访问对象看作是一辆公共汽车,把Windows NT看作是驾驶员,则“车票”是访问令牌的一个很好的比喻,乘客只有出示车票才能搭车)。图14.1描述了这两种结构。

图14.1 访问令牌定义了用户的权利,而 安全 描述符则定义一个进程的保护级别
以上,你只是稍微了解了一点Windows 95/98或Windows NT的 安全 性,简单地知道了它有 安全 对象和用户访问令牌,这与帮助你理解和使用Windows 安全 API函数还相差很远。在下面几节中,我们将细致地学习访问令牌是如何工作的;我们也将关注一下 安全 描述符。如果你只是对Internet感兴趣的话,在你使用ActiveX实施 安全 性时,可以完全不必懂得这些知识。然而,学会它,将会帮助你设计出更加符合心意的ActiveX控件。
理解访问令牌 
在Windows中,你将发现有两种方法可以查看用户的权限,而且两者都是通过这样或那样的形式与对象关联的。用户的访问令牌有一个 安全 标识符(SID),它在整个网络中识别用户棗它就像是一个帐户号。 安全 识别符表示了用户归属的组和拥有的优先权。每个组也有一个 安全 识别符,所以,用户的 安全 识别符也包含了他所属各个组的SID,并将引用这些SID。在Windows NT下,要想改变用户访问令牌的内容,你应该正规地使用用户管理器。
注 Windows NT支持两种类型的 安全 标识符(SID):用户SID和组SID
那么访问令牌的优先权是指什么呢?首先是用户拥有特权数——不是用户所归属的组的数目,而是指访问令牌内指定的特权入口数,这部分还包括特权入口的阵列。每个特权入口还包括一个局部唯一的标识符(LUID)和一个属性掩码(Atrribute mask)。LUID实质上是一个指向对象的指针,而属性掩码能表述用户对对象的权力。组的 安全 识别符也与此雷同,它们包括一个特权计数和特权入口的阵列。
技巧 现在,你可以去看看Visual C++软件提供的Windows API帮助,找一找与 安全 标识符或访问令牌相关的API函数。例如,与SID相关的函数包括CopySID和AllocateAndInitializeSID;你会发现OpenProcessToken和GetTokenInformation函数也是非常重要的,它能在任何语言下保证应用程序 安全 正常工作。
观察访问权限传递 
你还该知道的一件事是:有些类型的对象,如果它的权限没有被其它SID终止,则可能会继承到它的最低节点。例如,如果你让一个用户对硬盘的“Temp”目录有读写的权限,则用户对该目录的子目录“TempStuff”也有相同的权限,除非你分配给这个子目录别的权限。对于容器对象也是如此,如果分配一个用户对容器对象的权限,如一个Word文档,则它允许用户查看这个容器下的所有内容,很多情况下甚至还有别的文件。由此看来,因为你可能会不经意地分配给用户过多的权限,所以使用 安全 审察来跟踪用户对服务器中各类对象的确切权限,是非常重要的。
使用访问令牌  
因为访问令牌函数是你实施 安全 性前必须了解的第一个难点,下边,就让我们简要地谈论一下Windows 提供的访问令牌函数。对用户的帐户做任何工作,哪怕是找出谁在访问指定的工作站,都必须了解访问令牌。正如前面所讲的,访问令牌是 安全 等式用户方的中心部分。在对一个用户的帐户进行访问时,你几乎总要用到的一个函数是OpenProcessToken,请注意这个函数的名字,它能够处理的对象可以是任何类型的进程、线程或用户等等,该函数的作用是获取附加在这个进程上的令牌句柄。例如,如果你查询一个用户的帐户,你必须有TOKEN_QUERY优先权,(你的访问令牌中必须包括系统委托的一些必要的权限,这就是为什么管理员能访问某个令牌,而其它用户却不能访问的原因)。而对用户的帐户要做任何改动时,你必须拥有TOKEN_ADJUST_PRIVILEGES优先权。还有许多其它的访问权限,我们在这里不再一一表述了。
一旦你拥有了一个访问令牌的句柄,你需要决定将对它做些什么。如果你想改变用户做某事的优先权,则你将需要这个优先权的局部唯一标识符(LUID),所有这些优先权在WINNT.H文件中都是以“SE_”开头的。例如,SE_SYSTEM_PROFILE_NAME 优先权允许你收集这个系统的配置信息。有些SE的值与用户无关(例如,SE_LOCK_MEMORY_NAME特权允许进程锁定内存中的物理页面)。通过调用LookupPrivilegeValue函数,你可以获取对应局部系统上的优先权的LUID。一般而言,你将使用AdjustTokenPrivileges函数来实现你所需要的修改。
注 在WINNT.H文件中,查看一下Windows NT定义的优先权列表,这些优先权是你能修改的。
查询用户帐户(或访问令牌的其它信息)是直接了当的。你可以调用GetTokenInformation函数来获取你需要的信息,这个函数需要一个令牌类参数,它把你所需信息的类型告诉Windows系统。例如,如果你想知道一个指定用户的信息,你应该使用TokenUser类参数,你也将需要提供相应的结构,以让Windows保存你请求的信息,这一点与基于令牌类的请求不一样。
了解安全描述符 
现在让我们来关注一下 安全 描述符。在图14.1中,每个 安全 描述符包括五个主要的部分。第一部分是一个标志列表,这些标志指明了描述符的版本号、格式和访问控制列表(ACL)的状态。 
接下来的两部分包含了多个 安全 标识符(SID),所有者标识符表述了对象的拥有者,这不必是一个单独的用户;Windows也允许你在这里使用组的SID。有一点是受限制的,即组的SID必须出现在想要改变入口的人的访问令牌中。组标识符允许一组人拥有某个对象。这两种标识符中,只有所有者标识符在Windows下是重要的。组的标识符作为一个部分用于Macintosh和POSIX的 安全 环境。
最后两部分包含了各种访问控制列表(ACL)。 安全 访问控制列表(SACL)控制了Windows的审计功能,用户或组每次访问一个对象时,这个审计功能便启动了,Windows在审计记录中产生一个登记项;全权访问控制列表(DACL)控制了谁能真正使用某个对象。你可以将一个组或用户分配给一个指定的对象。
注释 实际上,有两种型号的 安全 描述符:绝对 安全 描述符和自身 安全 关联描述符。绝对 安全 描述符在它的结构中包含了每个ACL的真正拷贝,这种类型的 安全 描述符用于需要指定句柄的对象;而自身关联 安全 描述符只包括了指向SACL和DACL的指针,这种描述符在改变组的权限时,节省了内存并减少了所需时间,当某个特定组内,所有对象需要同一级别的 安全 性时,你应该使用它来处理,例如,通过这种方式,你能将单个进程内的所有线程赋予 安全 性。在你要保存 安全 描述符或将它传送给别的进程前,Windows 要求你把一个自身 安全 关联描述符转换成绝对 安全 描述符。通过API函数获取的描述符都是自身关联类型的,你必须在保存它之前将其转换。通过对MakeAbsoluteSD和MakeSelfRelativeSD两个API函数的调用,你可以在这两种类型的描述符之间转换。
一个ACL由两种类型的表项组成:第一个表项是个结构头,它列出了ACL包含的访问控制表项(ACES)个数,Windows使用这个数字检测是否到达了ACE列表的末端(这里没有任何其它记录或手段能够检测每个ACE的准确大小);第二个表项是个ACE数组。
警告 不要手工直接修改ACL或SID的内容,因为在以后的Windows版本中,微软可能改变它们的结构。Windows API为改变这些结构的内容提供了丰富的功能。如果要对某种结构进行任何的改变,请通过调用API函数来实现,以免不必要的冲突。
那么什么是访问控制项呢(ACE)?ACE定义了单个用户或用户组在一个对象上的权限。每个ACE由三部分组成:首先是一个结构头,它定义了这个ACE的类型、大小和一些标志;接着是一个访问标志,它定义了一个用户或组对这个对象的权限;最后是用户或组的 安全 访问标识符(SID)的项。
一共有四类ACE头(其中有三类已用于当前的Windows版本中)。其中,access-allowed类出现在DACL中,它认可用户的权限,你可以使用它增加用户对一个对象的权限。例如,虽然你想通过禁止用户修改系统时间,以使网络上所有机器的时间同步,但白天还是可以修改时间,而用户需要有这个权限,你可以通过使用一个access-allowed类的ACE来给予用户改变时间的权限;另一类是access-denied类,它废除用户对某一对象的权限,在一个指定的系统事件中,你能够使用它来拒绝对某一对象的访问,例如,当你对某一远程终端进行某些更新时,你可以取消其他人对它的访问权限;还有一类是system-audit类ACE,它与SACL一起作用,它定义了指定的用户对哪些事件进行审查。当前还未使用的是系统警报ACE,它允许SACL或DACL设置一个指定事件发生时的警报。
注 在当前的Windows NT版本中,使用的三类访问控制项(ACE)是access-allowed、access-denied和system audit。 
技巧 现在,你可以翻阅一下Windows API的帮助文件,看看Windows提供了什么类型的访问权限。为了获得这些信息,你应该更关注各种类结构,尤其是ACL和ACE的结构。看看ACE标志,它决定了在一个容器下的对象是如何作用的。例如,查一下CONTAINER_INHERIT_ACE常数,它允许子目录继承父目录的 安全 特性。
使用安全描述符 
到现在,你只是了解了什么是 安全 描述符,以及它包含的各类结构是如何相互作用的,你还应该知道怎样开始一个实际的访问进程,并使用 安全 描述符来写一个程序。你必须首先了解的是: 安全 描述符不同于访问令牌,它没有普及开,所以你不能使用一个标准的函数集来访问它们。实际上,一共有五类 安全 描述符,每类 安全 描述符都使用不同的函数集来访问对象。(你必须拥有SE_SECURITY_NAME特权,才能使用这些函数)。
到现在,你只是了解了什么是 安全 描述符,以及它包含的各类结构是如何相互作用的,你还应该知道怎样开始一个实际的访问进程,并使用 安全 描述符来写一个程序。你必须首先了解的是: 安全 描述符不同于访问令牌,它没有普及开,所以你不能使用一个标准的函数集来访问它们。实际上,一共有五类 安全 描述符,每类 安全 描述符都使用不同的函数集来访问对象。(你必须拥有SE_SECURITY_NAME特权,才能使用这些函数)。文件、目录、管道和邮件槽。通过使用GetFileSecurity和SetFileSecurity函数,可以访问这种类型的对象:
注释 只有Windows NT下的NTFS文件系统提供了 安全 特性。Windows 95/98下的VFAT文件系统只提供了很少的 安全 特性。你不能从HPFS或FAT文件系统中分配或获取 安全 描述符。FAT文件系统没有提供任何扩展属性的空间,而这些空间是增加 安全 性所必须的;HPFS文件系统虽然提供了扩展属性,但它们没有任何 安全 特性。在上述的这些文件系统中,NTFS是最 安全 的。然而,不要错误地认为会有完全 安全 的文件系统。在Internet上,有一些应用程序能够读取NTFS分区的内容,即便用户没有正确地登录到Window NT中。
要访问进程、线程、访问令牌和同步对象,你必须使用GetKernelObjectSecurity和SetKernelObjectSecurity函数。所有的这些对象都是内核对象,为了更好地保护这些对象,它们也都有自己的 安全 描述符。
要访问Windows 站点、桌面、窗口和菜单,你可以使用GetUserObjectSecurity和SetUserObjectSecurity函数。一个Windows 站点包括键盘、鼠标和屏幕,即你用来访问系统的所有硬件。桌面包括窗口和菜单。这四个对象按此次序依次从前一个对象继承权限,也就是说,桌面将继承站点的权限。
要访问系统注册键,你必须使用RegGetKeySecurity和RegSetKeySecurity函数。注意,Windows提供的所有注册类的函数都是以Reg开头的。 可执行服务对象,QueryServiceObjectSecurity和SetServiceObjectSecurity函数用于可执行的服务对象。奇怪的是,在Windows 的API帮助文件中,这两个函数都没有出现在其它 安全 函数的引用中。你在寻找这些函数之前必须已知道有这么两个函数。可执行服务是Windows提供的后台任务,如UPS的监视功能。通过双击控制面板中的服务程序,你将找到你的系统所支持的服务。
一旦你获得对某个对象的访问权限,你将发现,通过使用一般的API函数集,你便能够处理很多任务。例如,GetSecurityDescriptorDACL能够从任何类的描述符中获取一份DACL的拷贝。换句话说,这些对象的描述符跟随一个同样的格式棗即便大部分成分的描述符长度不同。导制这些长度不同的原因之一是,它们各自包含了不同数量的访问控制项(ACE),另外, 安全 标识符(SID)的长度也不同。
要查询或修改一个 安全 描述符的下一步工作是分离这些成分。例如,通过使用GETACE API函数,你能够查看在一个DACL或SACL中单独的ACE;通过使用与SID相关的函数,你也可以使用所有者标识符或组标识符(我们已经在本章的访问令牌部分阐述了这些函数)。可以满意地说,只要按指定的步骤做,你便能够使用一般的函数集来操作 安全 描述符。大致上说,对 安全 描述符的任何访问,一般都要经过下述三个步骤:
1. 获取描述符
2. 删除指定的成分
3. 修改指定成分的内容
要修改 安全 描述符,你应该按相反方向执行这些步骤。换而言之,你先使用类似AddACE函数来增加一个新的ACE至一个ACL;然后,使用SetSecurityDescriptorSACL来改变一个描述符中的SACL;最后,使用类似SetFileSecurity的函数(假设你想要修改一个文件对象)来保存 安全 描述符。
Windows中的ACEing安全性 
当你开始考虑Windows在DACL中计算ACE的方法时,你也许会发现一些潜在的存在问题的地方:虽然Windows的系统应用程序会自动关注这些问题,但你必须在自己应用程序中编制好了,才能运算出同样的结果。(SACL也有同样的问题,但它只是影响审查,从系统 安全 的角度看,它不是那么要求苛刻的)。
Windows 是按照ACES在ACL中出现的次序来计算访问控制结果的。首先,它可能不是一个很好算法,而且,在某些情况下它还会产生一些问题。例如,如果你想废除所有用户对某一区域的权限,但是在他或她的访问控制列表中包含了一个能够访问这一区域的组(即他或她是这一组的成员),这种情况的结果会如何呢?如果你将access-allowed 访问项放在列表的第一位,则这个用户将能够访问这一区域棗一旦Windows发现第一个满足用户所需权限的ACE时(或者一个禁止所需的权限的ACE时),它将停止继续搜寻。许可的权限是累加的,如果一个ACE允许对一个文件进行读的权限,而另一个允许写的权限,则当用户询问读和写的权限时,Windows 将综合这两个ACE并允许用户进行读写。下面的注中表示你应该将所有access-denied访问控制项放置列表前端,以防止 安全 上的潜在漏洞。
注 ACE在ACL中排列的先后次序是非常重要的,因为Windows 按次序对它们求值,并一旦发现第一个ACE允许或拒绝对某一对象的访问时,便停止继续搜索。
你也必须注意组的 安全 标识符(SID)的排列次序,因为用户从他(或她)所属的组获取的权限是相累加的。这意味着,如果一个用户属于两个组,其中一个组对某个文件有访问的权限而另一个没有,假如允许访问的组在列表中排列在前,那么用户可以访问这个文件,否则不能。
显而易见,为了将组排列成最好的次序,你将花费很多的时间。当用户拥有的组的权限和独立的权限数增加时,则可能出现无意识的 安全 漏洞。所以,仔细地创建一个组并严格限制用户单独的权限是非常重要的。
其它安全考虑  
当你关注在Windows 95/98或Windows NT下的 安全 性时,还有两方面需要考虑:数据保护和服务器保护。前者对付客户的这种能力:当客户通过服务器(这里不是指文件服务器,而是某些类型的DDE或其它应用服务。)访问数据时,访问了那些没有获准访问的数据。我们用这种方式思考一下:如果客户对某一指定类型的数据没有访问权限,但是通过调用他有权访问的DDE服务器访问了这些数据,这将会有什么后果呢?服务器又应该如何保护它们的数据,而不是被迫成为造成 安全 破坏的同谋呢?
Windows 提供了一些API函数允许服务器模仿一个客户。大体上是:为了检测出客户是否对一个数据或进程有过多的权限,这些函数允许一个服务器假扮成客户所受的 安全 限制。例如,Windows的一个Word用户可能需要访问Excel的一个数据文件,而这个用户可以通过DDE来获得这个文件的访问,在这种情况下,服务器需要检测一下这个用户是否有权访问这个文件,然后才传送所需的数据。当用户使用这种技术时,服务器甚至能找出客户的优先权。服务器唯一关心的是对它所管理的数据、资源和环境的保护。 
这个API函数集支持三种不同类型的通信:DDE、命名管道和RPCS。对每种通信类型,你必须使用不同的API函数。例如,要模仿一个DDE客户,你应该使用DDEImpersonateClient函数。Windows目前在模仿这方面所提供的支持还有一些限制。例如,它现在还不支持TCP/IP连接,所以在这种情况下,你必须依靠别的手段来检测一个用户是否有合适的访问权限。
另一个 安全 考虑是如何保护服务器自身。在一个Windows Word用户调用Excel服务时,用什么方法来防止这个用户对Excel服务器本身进行破坏呢?请确信,对文件和其它有名字的结构,服务器自动会附加上一个 安全 描述符到这些对象上,并进行严格的保护(一个DDE服务器,如Excel,在这种情况下不需要任何 安全 描述符,因为文件已在文件服务器的控制之下)。然而,大多数DDE或应用服务器的私有对象没有命名,它们需要另外的保护。Windows也提供了一些API函数来帮助服务器保护自身。例如,CreatePrivateObjectSecurity函数允许服务器附加 安全 描述符到它的任何私有对象上——如线程或其它进程。这些 安全 描述符能够防止除服务器外任何人访问其私有对象。
私有通信技术(PCT) 
微软和IETF正携手开发一个名叫PCT的新的底层协议,和 安全 套接层(SSL)一样,PCT是用来防止 黑客 窃听服务器和客户间的通信的,它通过加密、身份认证和数字签名技术来实现通信的 安全 性。由于可以使用SSL,所以客户身份认证可以根据需要进行选择。 
Web链接 如果想了解有关PCT当前的进展情况,请访问http://www.lne.com/ ericm/pct.html,这个文档中包括了PCT的第二个版本的当前草案,另外,通过访问http://www.w3.org/security/,你也可以参考一下W3C的Web站点上有关当前Internet 安全 技术的详细情况,其中包括PCT和SSL。
PCT假设你有一个可靠的传输协议,它能取代类似TCP的协议。有些人把TCP/IP看成是一种唯一的协议,但这是错误的,TCP只是这些协议中的传输部分,而IP才是数据传输部分。IP不支持任何形式的数据加密,所以,当你使用TCP/IP时,你的数据对任何想看它的人都是开放的。使用如TCP/PCT或TCP/SSL协议将使你的通信 安全 化。PCT的第一个版本修正了在SSL中出现的一些问题,现陈述如下:
简化了的消息和记录结构。如果你没有使用客户身份验证,那么会话的重新连接在每个地址上需要一个唯一的消息;即便使用客户身份验证,重新连接在每个地址上也只需要两个消息。 
扩展的加密算法。PCT提供了比SSL更丰富的算法,这意味着它能支持更广阔的协议特性,而且这些协议特性的交涉是相互独立的。例如,公共特性包括加密类型、服务验证类型、散列函数类型和密钥字交换类型。 改进的消息验证密钥。在PCT中,消息验证密钥和加密密钥是相互独立的,这意味着,即便加密密钥是短的或不存在的,只要消息能使用一个很长的密钥,也能保证传输的 安全 ,导制这一特性的主要原因是:因为美国政府把管理 安全 传输的密钥限定为最长为40位。
修补了 安全 漏洞。PCT在会话中的客户身份验证是基于加密算法的。这防止了某些人通过捕获客户的验证密钥,并切断原客户的会话,而使用窃取的密钥来建立重新连接。客户只有知道了密文和密钥,才能获得服务器的访问。
附加的提前检验区域。客户和服务器在最初的握手对话过程中,其通信是透明的,这个附加的区域使得客户和服务器可以检测在这种通信中可能出现的任何损害。
注释 虽然SSL在版本3中也提供了提前检验区域,但 黑客 也能够通过将协议版本号修改成2来绕过它,因为版本2中没有提供这一功能,而版本3完全兼容版本2,所以客户和服务器都不会注意到这个变化。
微软当前正在开发PCT的第二个版本,这个版本与第一个版本完全兼容,但提供第一个版本所不具有的几个重要特性。以下是这些特征的简单概述。
新的数据报记录类型 单独的记录作为“数据报”独立地发送,从本质上看,这意味着协议不会保证数据发送的次序或到达目的地址的次序,这要求客户将接收到的数据进行排序,然后检验它们是否全部到达。这种方法的最大好处是提高了传输速度。
可重新识别的记录类型 记录的头包含了一些信息,它告诉接收者将接收什么类型的记录。
连续记录 PCT版本1中允许数据跨越多个记录,即便是记录头没有指明连续的任何形式,版本2的记录头中增加了连续区,它也允许协议信息跨越多个记录。
数据记录的中间处理 数据记录是封装的,它允许发送者对数据做一些中间处理,比如压缩。
数据报记录的独立解密 由于发送的数据报记录可能会通过一个不可靠的传输通道,所以这部分特性对 安全 通信是非常重要的。每个记录分别加密,使得接收者可以立即对数据报解密,而不管接收数据报是否打乱了次序。
新的密钥管理记录类型 这个记录类型允许发送者在会话中临时改变加密或消息验证密钥。重要的是,这允许了PCT来传送预先加密的数据。 新的关闭连接密钥管理消息 这是一个特定的消息,它告诉其它参与者关闭连接。因为这个消息是加密的,所以 黑客 很难发送一条伪装的消息来关闭这些连接。
增强型消息验证 消息验证现在也包括了记录头。
改进的握手协议 客户和服务器端的验证都包括了更加丰富的选项,其中有密钥交换、签名公共密钥和证书。
新的私有验证特性 这个特性允许客户和服务器使用预先一致共享的私有密钥进行验证,而不是使用公共密钥。
既然我们对PCT有了一些基本的了解,那就让我们看看PCT是如何工作的。PCT使用可变长度的记录作为通信的方法,每个记录包括一个记录头,它定义了记录内的信息类型。一共有两类信息:应用信息和协议信息。应用信息总是包含数据,它们可以用标准的PCT格式或数据报格式;协议信息包含了密钥管理、错误或握手信息。PCT使用两种附加的层,记录总是使用一个连接传送。客户和服务器间一般只有一个连接,但没有任何理由不能有更多的连接,每个连接只是会话的一部分。再强调一次,虽然你一般只能看到客户和服务器间的一个会话,但你确实可以用多个会话。(多会话可能需要客户和服务器间建立多个物理连接)。
PCT协议的连接由一个握手信号开始,这就是握手管理消息类型开始工作的地方。客户和服务器交换多个信息,首先是连接会话密钥的握手,或者说是客户和服务器决定一个用于相互对话的保密字。此时,客户和服务器也彼此进行验证。如果彼此认为对方不可信时,便不会进行这种握手;一旦客户和服务器都认为对方可信时,它们便约定好了一个用于信息加密的主密钥。
HTTP上的Windows NT认证 
Windows NT的认证一般不是编程者要考虑的问题,更重要的是网络设置时要考虑的问题。但作为程序员,你确实应该了解一下认证问题,特别是如果你计划使用Internet或Intranet工作时更是如此。Windows NT现在支持两种基本类型的认证。(虽然没有任何东西阻止一些人使用其它方法。)
技巧 如果你想使用Windows NT的质问/回答(challenge/response)特性,你必须使用Internet Explorer 2.0或更高版本的浏览器,其它浏览器当前还不支持这种实施 安全 特性的方法。
第一种认证的方法是Windows NT的质问/回答。这种认证方法依赖于服务器和客户密钥的通信,而没有用户输入的任何形式。在客户初始登录到系统时,服务器要求客户输入用户名和保密字,客户提供一个特殊加密的用户名和保密字,他还必须提供一个域名,因为客户必须在服务器的域内或在一个服务器所信任的域内。由于Windows NT的质问/回答在客户和服务器间自动使用加密通信,所以它比服务器提供的基本认证更加 安全 。
注 Windows NT提供的两种形式的认证是基本认证和质问/回答,使用质问/回答认证是最 安全 的。
Web链接 有时,你顺手便可阅读到有关Windows NT针对Internet 安全 性方面的信息。其中一个信息源是Rick的Windows NT信息中心即http://rick.wzl.rwth-aachen.de/ cgi -bin/isindex3.cmd, 这个Web站点涉及的一些内容,是你在微软的用户手册中所看不到的。例如,你将学会怎样使用Windows NT的各类第三方产品。在微软的方案中没有预先考虑到时,有些知识很值得学习。
那么客户是如何知道需要发送用户名和保密字到服务器的呢?服务器要求这些信息作为头的一部分,实际上,服务器发送了一个错误信息(401 AccessDenied即访问拒绝),它告诉用户需要一个 安全 访问。浏览器中实际上没有包括从服务器来的所有信息,懂得这一点是很重要的,因为你在浏览器中看到的只是服务器想要你看到的信息,它已经过浏览器筛去了头信息。例如,服务器一般必须告诉浏览器它正接收什么类型的信息,这样如果需要的话,浏览器便能够激活一个帮助。知道有这些头信息,对你了解在客户和服务器间的动态数据传输是非常重要的。
警告 如果你在你的站点上选择基本认证方式来实施 安全 性,你必须使用SSL来确保用户名和保密字传输的 安全 性。否则这些信息很容易被人破解,并利用它获得你的站点的访问。
第二种方法依赖于诸如SSL的数字签名技术。实质上,Windows NT将需要一个从客户机来的数字认证,客户也需要Windows NT的数字认证。这些数字认证可以从第三方厂家(如VeriSign)获得,它能够保证双方的一致性。我们将会在本章的另一节中看到数字签名技术的确切过程。你现在应该知道的是,数字签名是一种 安全 手段,它能够标识试图访问你机器的另一方。
当使用SSL时,实质上是Windows NT服务器需要客户的标识。Windows NT所获取的是由第三方厂家(如VeriSign)发布的认证和随同的一个公共的密钥。SSL在进行认证时,一共有以下六个步骤:
1. 客户发送给Windows NT一个没有加密的随机消息并伴随一个它的VeriSign发布的认证(它包含了客户的公共密钥),VeriSign发布的认证是使用VeriSign的公共密钥加密的。因为每人都有VeriSign的公共密钥,所以Windows NT能够将整个认证解开并准确地检查它;同样,没有人能够伪造一个他们自己的公共密钥——他们必须从VeriSign那里获得。
2. 一旦Windows NT确认它从客户那里接收到了一个有效的证书和公共的密钥,它将告诉客户发送一个它最开始发送的消息的加密版本。
3. 客户计算机计算原始随机消息的摘要,然后使用公共密钥对它进行加密。
4. Windows NT使用客户的公共密钥对这个摘要进行解密。
5. Windows NT 将解开的摘要和客户原始发送的随机消息进行对比。
6. 如果两个摘要匹配,这个客户便认证成功。
在这里,你可能会关心与管理员有关的问题,虽然Windows NT自身提供了这两种内建的方法来控制服务器的访问,但它并不阻止你创建ISAPI过滤器来扩编或替代这种标准的 安全 机制。我们在第13章看到了一些非常基本的过滤器,但你也可以干脆使用其它的方法。你所应该做的就是监视那些由服务器产生的 安全 事件,这些事件中最关键的是客户的认证请求。在监视客户认证请求过程中,允许你增加任何必要的措施来确认谁在访问你的站点。
注 ISAPI过滤器允许你改变Web服务器认证用户的方法。
使用数字签名 
要精通数字签名的技术是比较困难的,虽然可以做到,但很少有人愿意去尝试。你首先必须懂得的是,数字签名也可以看成是授予证书。你可以把它想象成驾驶执照,因为它们之间有类似的功能。数字签名能标识一些Internet对象、以及创建它的人和创建的时间,也能潜在地提供很多其它信息,如果这个对象正好是客户或服务器,数字签名将显示对象的当前拥有者。和驾驶执照一样,数字签名也有过期的时候棗它迫使提供商不断地实现它们的承诺,这些过期的数据也使得 黑客 在篡谋窃取证书上浪费许多无用的时间(因为每个证书都是一个分立的条款,所以 黑客 只学会如何窃取其中之一是没什么用的)。使用数字签名将帮助人们保持诚实,因为它迫使每个人通过一个中心核查点。在Internet上,使用数字签名做期货交易还避免了一大堆的问题:它不依赖于某个人来维护机器的 安全 性,现在你可直接对那些获得访问的人进行投资(这也意味着要对用户做某些级别的训练,让他们真正学会如何去使用这个特性)。
注 虽然代码符号处理(将在这一节的下载Internet部件部分进行讲述)现在还不是数字签名,但最终也将合并到数字签名中来。
实施数字签名是非常直接而简单的,尤其是对客户端。在大多数情况下,商家提供了标准的证书,它能被所有浏览器或服务器所识别,但在授予证书的实际过程中,它们使用的方式却有不同。例如,在图14.2中的Web页中便显示了其中的一个潜在的问题,如果你想要获得一个客户的证书,你将选择哪个等级呢?(因为Class 1 Digital ID 证书 的价格便宜,所以许多人将会首选它)。

图14.2 客户端的认证将是未来Internet 安全 性的一个重要部分,但到底选择哪种认证并不容易
从实施的立场来看,你获得了Class 1还是Class 2证书对你的 安全 实施并不重要,即便是厂家,也不真正重视它。然而为了兼容性,你可能仍然想坚持用VeriSign(其实不然)。事实上,不同厂家使用数字签名的方法是非常相似的,因为它们的界面都是由Web服务器或浏览器所定义的,你将要做的只是接受一个应用程序,当厂家核查了你的身份后,你将会在e-mail中获得一个PIN或其它方式的证明,关键是要按照浏览器或Web服务器的提示安装这个证书。例如VeriSign公司,你进入它的Web站点并输入你的 PIN后,浏览器将自动关注下载和安装的细节。下述段落对VeriSign的证书等级作了一个概述。
Class 1证书,它在一个资源库内提供用户唯一的名字和地址,VeriSign(或你选择的任何其它厂家)将能够核查这个人的姓名和地址。回发e-mail是VeriSign用来发授证书的唯一手段,要接收这个证书,你必须拥有一个e-mail地址,这种方式使得 黑客 很难伪造这个证书。这种级别的证书每年需花费9.95美元(你也可以获得一个Class 1证书的免费测试版)。
Class 2证书,要获得Class 2证书,必须由第三方认证你的身份(目前只对美国和加拿大人授予Class 2证书)。Class 2和Class 1的最大区别是VerSign公司实际通过EquiFax公司提供的用户数据库来检测你的信息。你也通过一个硬件签名处理,它需要多个密钥。这种级别的证书每年需花费19.95美元。
如果你想获得一个证书并希望它能和多种软件协同工作,那么你不能只看它对浏览器的兼容性,因为数字签名技术有很多的标准规范(请参看表14.1),你将发现大部分的数字签名认证厂商已接近这些标准了。
如果你已经有了一个数字签名的证书,并分配给了你的ActiveX控件、Web服务器或浏览器(或以上所有的部件),那么你怎样鉴别其他人有没有证书呢?在你访问不 安全 的站点时,你总看到一些警告对话框,而访问一个有数字签名证书的站点也与之类似,你将看到一个如下图所示的数字签名证书。

注意,这个对话框还给了你一些优化选项。首先,你要检测证书的有效性,例如,检测它显示的厂商是否是你所期望的那一家;检测其日期来判断是否过期。其次,如果你想要到这个厂商那里去,你应该有能力通过其审计。在证书下的第一个检测框总是允许你在列表中增加一些由WinVerifyTrust检测过的指定的公司(我们在第8章讲述下载过程中提到过WinVerifyTrust),如果你选择这个厂商,则每次需要在这个指定的公司下载东西时系统将不再提问,这对访问某些站点来说可能有点冒险,但也许没比这更好方法了,它完全决定于你对这个公司的信任度;第二个检测框允许你对所有授予了指定证书代理权的商家进行访问,如VeriSign,如果你的认证过程很舒适,你可以不选中这个检测框。
你也许正为要对ActiveX控件所做的这些事而感到惊讶。用户和Web的主人一样,如果你决定使你的站点公共化,你将发现自己在某些地方需要这些证书。因为人们不愿下载一个未经数字化标识或看不到厂商证书的控件。取得证书的过程应该与我们刚看到的浏览器用户获取证书的过程没有太大的区别。你现在不必立即拥有一个证书来标识你的控件,但在不久的将来,它是必不可少的。我们将在本章有关下载Internet部件的部分,介绍标识ActiveX控件的实际过程。
理解加密API 
到此为止,防止某些人偷阅你的数据一直是本章所有内容的主题。我们已经学习了一些 安全 协议和技术,它们能帮助你将 黑客 拒之门外。然而,只要有充分的时间,任何一把坚固锁都可能被人撬开。事实上,这就是为何要使用128位的密钥代替40位密钥的原因。由于解开128位的密码“锁”需要太多的时间(至少现在是这样),所以包含在这个记录内的数据对 黑客 几乎没有吸引力。 黑客 当然也能打开这把“锁”,但非常困难。
保护层 
增加保护层是针对 黑客 的另一种利器。对数据进行多种级别的加密并加上“防盗门”, 黑客 要获得数据必须通过这些“门”。只要在你的数据和 黑客 之间放置足够多的“门”, 黑客 便很难攻破它。
微软的加密API(或加密应用程序接口)增加了保护层类。它意味着你又可以对敏感数据增加一个保护层了。这里支持的加密技术虽然并非坚不可摧,但 黑客 要解开它读取你的数据,确实需要花费更多的时间。使用加密API函数将帮助你更好地保护服务器和客户间的数据传输。
Web 链接 对于其它涉及Internet的东西来说,加密API(CryptoAPI)是全新的东西,并且还在不断地发展之中。在撰写本书时,加密API只是作为ActiveX SDK的一部分来叙述的,你应该通过Internet下载它的一个详细说明。虽然本书在这一部分提供了最好的叙述,但你还是应该访问一下加密API站点http://www.microsoft.com/security/tech/misf6.htm,以获得最新信息。
加密API还有其它一些用途。因为加密API是作为一个通用 工具 而设计的,所以它允许在任何环境下对数据进行加密,而不只限于Web服务器。例如,你可以创建一个应用程序将所有存储数据使用相同的加密格式,这些数据可以是存储在本地的、通过modem传输的、上载到一个Web站点的,或是通过邮件发送的。这将给你的公司带来很多的好处:对敏感数据进行随时加密,使得 黑客 即便闯进了你的系统,也很难破解你的数据。然而,使用加密技术,也会给你的用户带来一些不便,可以预料,只要加密操作变得更加方便和自动化,你的用户肯定会喜欢上它的。让攻击者的攻击变得困难、摸不着头绪,或者简单地要他们花费更长的攻击时间都是吸引用户的最佳途径。这样麻烦不断的用户就会确信应该在你的系统中保护他们的数据。
注释 Windows NT 4.0内建了加密API 1.0(CryptoAPI 1.0)支持。当你安装完服务器修补包3后,其支持的等级将升级至2.0。这两个版本的最大区别是:加密API 2.0支持核心加密,它允许开发者在应用程序内纳入加密,而且加密API 2.0还支持X.509证书、ASN.1编码、PKCS#7和PKCS#10压缩。你将发现,Visual C++需要有WINCRYPT.H和CRYPT32.DLL文件,才能提供CryptoAPI 2.0的支持。
CryptoAPI 是模块化的,这并不足以为奇,因为在过去的几年里,微软将它的操作设计转移到了模块化的方式上。我们可以拿CryptoAPI与Windows下的GDI(图形设备接口)API相比较,任何厂商都能够增加新的设备驱动程序来告诉GDI如何和指定的显示卡工作。CryptoAPI也是如此,它采用了加密服务提供者(CSP)的思想。虽然Windows本身已有微软提供的CSP,然而,如果它的加密特性还不能满足你的需求时,你也可以自己设计一个新的CSP或从别的公司购买一个。CSP的安装过程就像是增加一个设备驱动程序一样。事实上,这种设备驱动程序的方式使得在你的机器上可以混合加密硬件和加密软件,这是一个真正的提高点,因为你通常是将硬件和软件作为分立的实体来安装的。
Web 链接 微软已经为CryptoAPI开发了一个DDK(设备驱动程序开发 工具 ),Cryptographic Service Provider Developer's Kit(CSPDK)。你可以通过http://www.micorsoft.com/devnews/novdec96/crypto5_6.htm获取更多的信息。
加密一个文件 
为了显示一下CryptoAPI提供的机能,下面举一个加密文件的例子。加密文件是相当简单的,微软直接依照八个步骤处理(其中六步含有特定的加密函数)。最开始,你象在其它编程中一样,打开一个源文件和目标文件(例子中的这部分代码用C语言编写,你也很容易在其它语言中实现),在你拥有一个有效的文件句柄后,你必须像下边的例子一样获得一个CSP句柄:


注释 在WINCRYPT.H文件中,你能看到与加密有关的函数、结构和定义的完整列表。
CryptAcquireContext()能够接收五个参数,但在这个例子中只有两个是重要的,第一个参数保存CSP的句柄,第二个参数指定你要查找的CSP类型。每个CSP都有一个名字和类型。例如,当前随Windows一起发布的名叫Microsoft BaseCryptographic Provider v1.0的类型是PROV_RSA_FULL。每个提供商的名字是唯一的,而类型却不是唯一的。第二个参数包含了密钥的容器名,如果你在这里输入一个值,Windows将寻找一个指定的密钥容器,厂商可以在硬件里、注册表中或硬盘里保存一个密钥容器,所以你一般不会知道密钥容器的名字,如果使用NULL值(如例子中所示)将告诉Windows返回默认的密钥容器;第三个参数包含了CSP的名字,你可以通过使用CryptGetProvParam()函数来取回这个值,填写NULL值将返回默认的CSP;最后的参数包含了一个或多个标志,如果CSP没有提供指定的标志值,你可将这个参数设置为0(微软只为管理方面提供了一些默认的标志值)。
下一步可以是使用一个随机密钥或由口令产生的密钥来加密文件。随机密钥方式在ActiveX控件中使用的可能最为频繁,所以在此加以描述,口令方式也与之类似,而实际需要的步骤比随机密钥更少。
//创建一个会话的随机密钥
if(!CryptGenKey(hProv,ENCRYPT_ALGORITHM,CRYPT_EXPORTABLE,&hKEY))
{
MessageBox("Error during CryptGenKey",NULL,MB_OK |MB_ICONEXCLAMATION);
PostQuitMessage(1); 
}
CryptGenKey()函数提供给你一个唯一的密钥。注意第一个参数是CSP句柄,第二个参数包含了加密算法名。微软提供了两种加密算法:CALG_RC2(块密码)和CALG_RC4(流密码)。算法名会随着厂商的不同而变化,所以知道用户打算使用哪家厂商的CSP是很重要的。第三个参数包含了标志,一共有三个默认的标志值,CRYPT_EXPORTABLE告诉Windows能够输出一个随机的密钥到一个blob(我们将在随后看到它);CRYPT_CREATE_SALT告诉Windows给随机密钥种子值使用一些其它大于0的值;最后,CRYPT_USER_PROTECTED告诉Windows在某个动作发生时提醒用户。最后一个参数是存储返回随机密钥的一个容器。
在获取一个证书的过程中,用户将接收到一个公共密钥,CSP将这个密钥保存在一个中心位置——用它标识用户。为了保证数据传输的绝对 安全 ,在加密过程中,获取用户公共密钥的一份拷贝来使用是很重要的,这就是下一步所要做的工作。
//获得用于交换密钥的公共密钥句柄
if(!CryptGetUserKey(hProv,AT_KEYEXCHANGE,&hXchgkey))
{
MessageBox("ErrordwringCryptGetUserKey",NULL,MB_OK |MB_ICONEXCLAMATION);
PostQuitMessage(1);
}
我们提供给CryptGetUserKey()的第一个参数是CSP的句柄,第二个参数是表示从提供者那里获取什么类型的密钥。每个CSP将支持两种密钥:AT_KEYEXCHANGE(这个交换的公共密钥是为应用程序中的个人认证而提供的)或AT_SIGNATURE(与随后的ActiveX控件获取数字签名密钥一样),第三个参数提供存储返回密钥的空间。
我们现在进入了一个有趣的部分。我们获取随机密钥和用户的公共密钥,并将其混合使用,这意味着,即便用户的密钥在某些方面被破译了,数据还仍有另一种方式的加密,它迫使 黑客 又得重头开始破译。随机因素使得加密技术至少在 安全 上超过了其它方式的加密。
//决定键blob的大小并分配内存


注意输出Blob密钥(用户的公共密钥和随机密钥的组合)的过程,实际上有三步处理,我们调用了CryptExportKey()函数两次,头两个参数值是我们创建的密钥:随机密钥和用户密钥;第三个参数告诉Windows创建什么类型的blob,大部分CSP支持两种值:SIMPLEBLOB或PUBLICKEYBLOB;第四个参数是一些标志,除非CSP为别的目的而使用它,否则这个参数总设置为0;第五个参数是指向存储blob的缓冲区的指针,如果你在调用CryptExportKey()时将它设置为NULL,它将简单返回缓冲区的大小,这个大小在第六个参数中将用到,这就是我们在第一次调用它的目的;第六个参数一般包含了你实际调用CryptExportKey()创建blob时所需缓冲区的大小。(这里的源代码也包含了一个内存分配函数的调用)
既然我们已经获取了一个blob,那么现在该关注一下后续工作了,你马上要做的工作是销毁用户的公共密钥,因为 黑客 可以从你的内存中搜寻到你的密钥并破坏你的代码,所以从内存中将密钥删除,无论从内存的角度还是从编码练习的角度来看,这都是一个很好的策略,它对维护你的 安全 系统来说,是必不可少的。下面的代码是调用CryptDestroyKey()函数来删除公共密钥。
//释放键交换密钥的句柄
CryptDestroyKey(hXchgKey0;
hXchgKey = 0;
在这时,你可以将blob数据保存到磁盘或硬盘内的一个文件中。blob实际上组织了一个头,接收的机器将使用它对文件进行解密。然而,一个没有数据的头并不好,这就是我们下一步所关注的,你要做的第一件事就是定义数据块的大小,如果你使用块加密方式,CSP将提供块大小,块加密一般需要你在文件的尾部增加一个附加的空白块。当使用流加密时,你可以定义任何大小的加密块(尽管微软推荐使用1,000字节的块大小)。现在你将数据一块一块读取到缓存,并使用以下代码对它进行加密,然后将数据块写入目标文件中。
//对数据进行加密
if (!CryptEncrypt(hKey,0,eof,0,pbBuffer,&dwCount,dwBufferLen))
{
MessageBox("Error during CryptEncrypt",NULL,MB_OK|MB_ICONEXCLAMATION);
PostQuitMessage(1);
}
你可以设计一个循环来不断地处理数据,直到读完数据块为止。确认你填充了所有不满的块,CryptoAPI甚至将块大小作为加密处理的一部分。

windows NT的安全性相关推荐

  1. 使用Windows NT 的安全性(转)

    使用Windows NT 的安全性: 在上一节,我们已经阐述了推荐使用Windows NT做Web服务器的一些理由,其最重要的一点是,能够使用Windows NT的安全性API.然而,懂得为什么要存在 ...

  2. Windows系统回顾之Windows NT

    在Windows3.X的成功之后,Microsoft开始将操作系统的发展分为两线,其中一个是Windows 3.X的下一代产品Windows95,另一个则是全新的操作系统Windows NT.在Win ...

  3. Windows NT体系结构

    Windows NT中的NT意为New Technology,其实Microsoft自从93年推出的第一个windows NT 3.1到即将发布的windows 7都属于NT版本的范畴,只不过是Win ...

  4. 计算机专项能力局域网管理,全国计算机信息技术考试局域网管理(Windows NT平台)管理员级考试考试大纲...

    全国计算机信息技术考试局域网管理(Windows NT平台)管理员级考试考试大纲 时间:2013-12-25 19:55:12  来源:IT认证考试网  点击量: 更多 第一单元 计算机网络原理(10 ...

  5. [ZT]Inside WINDOWS NT Object Manager

    [ZT]Inside WINDOWS NT Object Manager Inside WINDOWS NT Object Manager ============================== ...

  6. Windows NT 简介

    Windows NT Microsoft Windows NT即视窗NT是由 微软公司发行的操作系统. Windows NT是基于 OS/2 NT的基础编制的.OS/2是由微软和 IBM联合研制,分为 ...

  7. VMS和Windows NT的首席设计师大卫·卡特勒(David Cutler)

    David Cutler VMS和Windows NT的首席设计师大卫·卡特勒(David Cutler) 出生日期: 329次关注 VMS和Windows NT的首席设计师,曾经是惠普公司的Unix ...

  8. 为什么某些Win32技术在Windows NT服务中行为不当?

    弗兰克·金 服务是具有特殊要求的后台Win32进程.它需要一个独特的入口点和一个回调函数.回调函数被称为服务控制处理程序.新的入口点通常称为ServiceMain,但您可以任意命名. 本文假定您熟悉W ...

  9. [转帖]windows7/windows NT介绍

    windows7/windows NT介绍 原文应该是IT168发布的 但是一直没找到 感觉看了之后 明白了很多 技术都是互相融合的 没有严格意义上的对立直说. Windows 7/Windows S ...

  10. 刨根问底:Windows CTF协议安全性研究

    0x00 前言 我自己经常会编写简单的测试案例,来验证后台处理逻辑与我设想的相符.有时候我无法解释测试结果,会刨根问底,最终挖掘出新的研究方向. 通常情况下,同一个桌面中的窗口之间可以互相通信.这些窗 ...

最新文章

  1. 文件解析库doctotext源码分析
  2. PTA 基础编程题目集 7-33 有理数加法 C语言
  3. 安卓学习UI组件-ExpandablelistView-可拓展的两级列表
  4. Ubuntu下ICE-3.4.2的安装
  5. STM32F103系列单片机学习笔记1方便以后查看
  6. 【三分钟刷一题力扣】移除元素
  7. 零件分组pascal程序
  8. Go的GOPATH与GOROOT
  9. Druid源码分析系列1:dataSource.init()的准备工作
  10. 网络爬虫_第二章_提取_第四单元_BeautifulSoup库入门(未完待续)
  11. Redis 响应延迟问题排查
  12. php 写入.csv文件注意点
  13. git包名大小写不敏感的百分百管用但是不完美的解决方法
  14. 【性能优化实战】日语java开发相关词汇
  15. Win10(winser2019)关闭驱动数字签名方法
  16. js数组的reduce方法
  17. python socket编程在阿里云的esc服务器下 [Errno 99] Cannot assign requested address解决方式
  18. 生物特征识别技术的安全性分析
  19. Python 3.6 使用wordcloud制作词云(可设背景图像)
  20. Oracle数据库基本使用

热门文章

  1. CGAL点云重建白膜
  2. 经典伴读_GOF设计模式_创建型模式
  3. XUI 熟练使用之(二) -----------轮播条( BannerLayout 的使用)
  4. 各种实用航测遥感数据数据免费获取,速来领取!
  5. 本周大新闻|Elbit推飞行员专属AR头盔,苹果第二代MR将分高低配
  6. 使用adb安装apk
  7. 需求分层-KANO模型解读
  8. 基于spring boot的人民医院体检预约系统
  9. 人工智能对摄影测量与遥感的影响与挑战——龚健雅院士
  10. *使用phpspider -- PHP蜘蛛爬虫框架来爬取数据