深蓝海域KMPRO

HTTP安全性和ASP.NET Web服务

2003-01-08 09:35

HTTP安全性和ASP.NET Web服务

摘要:目前,基于 HTTP 的安全机制是保证您的 Web 服务安全的最好方法。了解如何结合使用 Microsoft IIS 与 Microsoft ASP.NET 来保证 Web 服务的安全。

注意:本文假设您已经比较熟悉如何配合使用 SSL 和 IIS。
  
简介
  
有一个一直让 Web 服务开发人员感到头疼的课题,那就是:如何使 IIS 和 ASP.NET Web 服务协同工作以提供安全性。现在,我们通过 IIS 来处理安全问题,并通过 ASP.NET 进行调节。ASP.NET 可以接受 IIS 提供的身份标识信息并使用该信息来了解调用者是谁,或者利用代码访问安全性在 Web 服务上执行特定操作。对于许多人而言,最大的问题是如何使 .NET 应用程序利用内置的 IIS 安全保护功能。在不远的将来,WS-Security 将是您的更佳选择。在那一天到来之前,HTTP 级的安全保护将是我们许多人用来保证信息安全的方法。

当以安全的方式执行 Web 方法时,必须涉及以下各项:

保密使侦听对话的实体不能直接看到数据。

完整性向接收者提供对 SOAP 消息所作更改进行检测的能力。

身份验证回答“调用者是谁”的问题。

授权回答“调用者是否有权访问该 Web 方法”的问题。

认可证明所发生的操作,以防止客户端在事务处理中欺诈或否认。
  
这些安全保护功能常常是配合使用的。身份验证允许授权和认可的发生。SSL 提供的保密措施也包括完整性和身份验证机制。本文假设您已经比较熟悉如何配合使用 SSL 和 IIS。如果您不熟悉,请查看本文末尾的资源。同时,建议您查找安装了证书服务器的 Microsoft? Windows? 服务器,或者在可用的 Windows 服务器上安装证书服务器。这将对理解本文有关 SSL 的部分有所帮助。

使用 SSL 进行加密和签名
  
任何时候当您需要对基于 HTTP 的 SOAP 消息进行保密时,都应该通过 SSL 运行服务。它将对通过线路查看数据传输的实体隐藏 Web 服务中的数据。

为了使用本节中的数据,在您的 Web 服务器的根目录下必须安装有 X.509 证书。。正确安装证书后,您便可以为虚拟目录或特定文件选择强制执行 SSL 身份验证。

  
打开 Internet Information Services 管理控制台的步骤

在“开始”菜单中单击“运行”。

在“打开”编辑框中,键入 inetmgr。

单击“确定”。

这样,IIS 管理控制台就打开了。

为虚拟目录或特定文件请求 SSL 就是在 IIS 中选择正确的选项。要选择“正确的选项”,请浏览到 IIS 管理控制台中的虚拟目录。如果您想为可以通过给定的虚拟目录进行访问的所有 Web 服务请求 SSL,请右键单击该虚拟目录,单击“属性”,然后单击“目录安全性”选项卡。

如果只保护某个特定的 Web 服务,请右键单击与该 Web 服务关联的 .asmx 文件,单击“属性”,然后单击“文件安全性”选项卡。不管执行哪个步骤,您都将看到一个与图 1 类似的对话框。请在“安全通信”下,单击“编辑”,将打开如图 2 所示的“安全通信”对话框。

 

图 1:IIS 管理控制台中的“安全性”选项卡

 

图 2:“安全通信”对话框

默认情况下“需要安全通道 (SSL)”复选框没有被选中,请选中该复选框以请求 SSL。SSL 支持 40 位和 128 位加密。加密使用的位数越多,破译和找出原始位就越困难。这就是为特定的 .asmx 文件或整个 Web 服务启用 SSL 所要做的全部工作。这样,只要 Web 服务器的证书不受威胁,所有 Web 服务客户端和 Web 服务本身都将是安全的。SSL 使用包含公钥的 X.509 证书,可能还包含一个私钥。如果私钥被外部用户知道,则使用公钥加密的通信就可能会被外部用户侦测到,从而变得不安全。

一旦您将资源设置为通信时需要 SSL,则发送者和接收者之间传送的信息就将被加密并签名。也就是说,外部用户将无法阅读消息的内容。如果外部用户改变了消息的字节数,消息接收者可以检测到更改。

身份验证
  
为了利用 IIS 给您提供的身份验证,您需要编辑与您的 Web 服务关联的 Web.config 文件。要使用户的身份在 HttpContext 中可用,您需要将 /configuration/system.web/authentication/@mode 属性设置为 Windows。当 IIS 使用以下身份验证方式之一时,必须设置模式属性:基本、简要、集成 Windows 身份验证 (NTLM/Kerberos) 或 X.509 证书。上述任何一种身份验证提供的用户凭据都必须映射回本地计算机或 Active Directory 中的用户。

IIS 和正确的 Web.config 设置结合使用将使 Web 服务能够发现调用者的身份标识。作为新增的优点,请求上下文将假设调用者的身份。如果要利用 Windows 身份验证,Web.config 文件应该如下所示:

<configuration>
<system.web>
<authentication mode="Windows" />
<!-- 其他元素将放在此处 -->
</system.web>
</configuration>

为了处理身份验证、审核和认可,打开 Windows 身份验证是很关键的。这样做的目的是使您的 Web 方法以调用者的身份运行。所有记录、访问检查等都是根据用户的权限来执行的。

为了强制 IIS 提供调用者的身份标识,您需要告诉 IIS 关闭匿名访问。就是这么简单,真的。要执行此操作,请返回并打开 inetmgr(单击“开始”->“运行”,然后键入 inetmgr)。浏览到所需的虚拟目录。右键单击虚拟目录或 .asmx 文件(这取决于您需要对虚拟目录中的所有文件实施身份标识还是仅对一个 Web 服务实施身份标识),然后单击“属性”。单击“目录安全性”选项卡,如图 1 所示。在“匿名访问和验证控制”中,单击“编辑”。将打开如图 3 所示的“身份验证方法”对话框。

 

图 3:禁用匿名访问的“身份验证方法”对话框

“身份验证方法”对话框允许您配置用户访问虚拟目录或文件的方法。要通过 HTTP 信息头传递用户凭据,您可以使用基本或简要身份验证。基本和简要身份验证均不提供任何确保消息安全的机制。传递用户凭据的机制由 RFC 2617: HTTP Authentication: Basic and Digest Access Authentication定义。基本上,使用一个名为 Authorization 的 HTTP 信息头来传递用户名和密码。对于基本身份验证而言,用户名/密码组合是以明文的方式发送的。不过,也不全是这样。实际上,用户名和密码是使用简单明文形式的 base64 编码方法来发送的。如果您不熟悉 base64 编码,可以使用二进制数据并以文本形式提供这些数据。对数据进行编码时,不使用机密/密钥。如果选择使用基本身份验证,则只能接受通过 SSL 的凭据。这可以保护 Web 服务和调用者免受试图攻击通道以捕获有效凭据集的实体的威胁。

还可以使用简要身份验证。如果选择此选项,您必须了解,许多 SOAP 工具包都不支持简要身份验证。因而,可以使用 Web 服务的工具包数量将受到限制。如果想知道调用者的身份,而目标 SOAP 工具包支持简要身份验证并且 SOAP 消息的内容不是特别重要,则请使用简要身份验证。简要身份验证使用名为 nonce 的共享机密为调用者的凭据进行加密。

基本和简要身份验证都使用质询-响应机制。正因为如此,在 Web 方法调用发生之前,客户端和接收器之间将发送多次请求和响应。在基本身份验证中,质询和响应的速度都相当快。事实上,如果客户端知道需要基本身份验证,它会提早提供基本凭据。这种提速可以是需要验证服务器证书并建立会话密钥的、基于 SSL 的连接中的临界值。在简要身份验证中,在凭据被加密前,需要交换 nonce。同样,在 Web 服务代码被执行之前需要执行一些握手操作。

要针对 Web 服务强制启用这些项,只需要在“身份验证方法”对话框中选中相应的框即可。如果您确认只需要获取已经过身份验证的用户,请确保取消选中“匿名访问”复选框。完成这一步后,您便可以在服务器端进行以下操作:

搜索调用者。

使用代码访问安全性限制调用者可以调用的方法。
  
以下 Web 服务返回当前的调用者信息:

[WebMethod]
public string WhoAmI() {
return "正在作为用户运行: " +
Thread.CurrentPrincipal.Identity.Name;
}

我们将修改一个调用该 Web 服务的简单的控制台应用程序。开始时,客户端如下所示:

static void Main(string[] args) {
localhost.Sample svc = new localhost.Sample();
try {
Console.WriteLine( svc.WhoAmI() );
} catch ( Exception ex ) {
Console.WriteLine( ex.ToString() );
} finally {
svc.Dispose();
}
}

如果没有对 Web 服务/应用程序应用安全保护,Main 函数将打印以下信息:

 

图 4:无安全保护运行,因而也没有身份标识

如果您通过图 3 中的对话框关闭匿名访问,客户端将无法访问 Web 服务。相反,将显示以下错误消息:

System.Net.WebException: 请求失败,HTTP 状态 401: 访问被拒绝。

为什么会是这样呢?默认情况下,Web 服务代理不包含任何关于调用者或要传递的凭据的信息。因为不能验证自己的身份,调用 Web 方法的尝试失败,并且引发异常。如果您想为当前用户传递正确的凭据,最简单的方法是沿着当前用户的默认凭据传递。客户端中的 try 块需要进行修改才能读取:

svc.Credentials =
System.Net.CredentialCache.DefaultCredentials;
Console.WriteLine( svc.WhoAmI() );

它允许代理访问 Web 方法,因为它可以携带当前用户的凭据并将其提供给质询时的 Web 方法。Web 服务返回以下结果:

作为以下用户运行 : REDMOND\sseely

这将同时使用基本和简要身份验证。身份验证信息只对一个 Web 服务调用有效。换句话说,Web 服务代码不能调用其他 Web 服务,不能使用这些机制扮演调用者。请记住,如果您选择基本身份验证,则还应该为该文件请求一个 SSL 连接,以避免用户的身份被泄漏给监视连接的实体。有时,您可能需要使用不同于当前用户的身份标识来访问 Web 服务。那该怎么做呢?您可以“手动”设置凭据。

假设在本地 Web 服务器 sseely2 上有一个用户名为 Example,其密码为 Test$123。要手动设置凭据,必须创建一个 CredentialCache。使用 CredentialCache 的代码需要使用 NetworkCredential 对象填充高速缓存。当向高速缓存添加 NetworkCredential 时,代码需要指定返回指定凭据时所使用的 URL/身份验证组合类型。有可能使用多个站点的标识信息来填写高速缓存,并使高速缓存针对各站点和身份验证类型智能地返回正确的凭据。要将高速缓存设置为针对来自 Web 服务的基本身份验证质询发送正确的凭据,请使用以下代码:

localhost.Sample svc = new localhost.Sample(); try { CredentialCache credCache = new CredentialCache(); NetworkCredential netCred = new NetworkCredential( "Example", "Test$123", "sseely2" ); credCache.Add( new Uri(svc.Url), "Basic", netCred ); svc.Credentials = credCache; Console.WriteLine( svc.WhoAmI() );

当在 URL 中传递,以在包含 credCache.Add 的行上使用时,您会发现 URL 是从 Web 服务中得到的,而不是被硬编码或从其他源获取的。我喜欢用这种方法将调用编写到 Add 方法中,因为这样最省事,又可以保证 Web 服务端点和调用 Add 所使用的端点相同。

如果您想为简要身份验证使用相同的凭据,则向凭据高速缓存添加信息的行将读取:

credCache.Add( new Uri(svc.Url), "Digest", netCred );

基本身份验证将对在本地计算机注册或在目录中注册的用户起作用。简要身份验证只接受在信任的 Windows 域中注册的用户。

另一种验证 Web 服务调用者的方法是通过 SSL 执行相互身份验证。SOAP 消息的发送者和接收者可以交换证书并互相验证。服务器如果具有 SSL 功能,则将具有证书。如果以相同的形式向客户端签发了证书,则客户端也将具有证书。如果您已经具有一个证书服务器,您需要给自己签发一个证书,然后通过图 2 所示的对话框将证书映射到您的用户帐户中。

如果您确实有可用的证书,则可以通过控制面板中的“Internet 选项”小程序访问这些证书。访问此小程序的最简便的方法是通过 Microsoft? Internet Explorer。如果您没有安装证书,而现在想获取一个。只需打开 Internet Explorer,浏览到已安装证书服务器的 Windows 服务器。您所需的 URL 为 http://machine_name/certsrv。按照屏幕上的说明来请求和安装客户证书。下一步,在 Internet Explorer 的“工具”菜单中,单击“Internet 选项”,单击“内容”选项卡,然后单击“证书”。将显示一个与图 5 类似的对话框。

 

图 5:“证书”对话框

您需要导出一个证书,以便可以被 Web 服务代理身份验证使用。要导出证书,请单击“导出”打开“证书导出向导”。在向导中,单击“下一步”接受所有默认选项,然后选择一个写入证书的文件名。在我的示例中,我将证书保存到 c:\temp\secSample.cer 中。单击“下一步”,然后单击“完成”。现在,我们需要将该证书与某个特定用户关联起来。

重复执行请求 SSL 所需的步骤,以确保一个或所有 Web 服务的安全。

选择“启用客户证书映射”复选框,并单击“编辑”。

在“一对一映射”选项卡上,单击“添加”。

选择 c:\temp\secSample.cer

在“映射到帐户”对话框中,设置以下各项:

“映射名”:HTTP 示例映射

“帐户”:选择一个用户帐户。在我的示例中,我选择的是 sseely2\Example。

“密码”:映射到帐户密码。在我的示例中,我输入的是 Test$123。

如果证书身份和与证书关联的身份不匹配,那没有关系。将证书匹配到身份标识时,服务器只在存储区中查找与接收到的证书完全匹配的另一个证书。为什么是这样呢?个人也可能具有由公共证书颁发机构签发的客户证书。使用 SSL 客户身份验证时,服务器可以将证书映射到主机中的某个身份标识,而不需要与证书颁发者以任何方式发生关联。   

单击以确认密码,再单击三次“确定”关闭对话框。
  
现在,您需要在 IIS 中设置其他选项。首先需要清除所有可用的身份验证方法,以确保受保护的资源(.asmx 文件或虚拟目录)具有图 6 所示的权限设置。

 

图 6:所有身份验证方法都被清除

然后,需要客户证书,如图 7 所示。

图 7:需要 SSL 和客户证书

最后,需要对客户端进行配置,以从文件加载证书并提交给 Web 服务。System.Security.Cryptography.X509Certificates.X509Certificate 类知道如何读取 X.509 证书。要加载证书并使其可以被 Web 服务使用,请读入证书,并将其添加到代理的客户证书集合中。

static void Main(string[] args) { localhost.Sample svc = new localhost.Sample(); try { X509Certificate x509 = X509Certificate.CreateFromCertFile( @"c:\temp\secSample.cer"); svc.ClientCertificates.Add( x509 ); Console.WriteLine( svc.WhoAmI() ); } catch ( Exception ex ) { Console.WriteLine( ex.ToString() ); } finally { svc.Dispose(); } }

正如所料,输出为:

作为以下用户运行 : SSEELY2\example

使用基本/简要身份验证或 X.509 验证用户身份时,您也可以使用访问控制列表 (ACL) 来确定那些用户可以访问目录。一种查看文件或目录的 ACL 的方法是使用 Windows 资源管理器。右键单击文件,然后单击“属性”。在“安全性”选项卡中,您可以添加或删除用户和用户组,也可以对这些用户操作文件的权限进行管理。

您并不是任何时候都希望将 Web 服务的用户添加到 Active Directory。相反,将这些信息保存在别处可能更可取。要解决此问题,通常使用下面两种方法:第一种方法常用于安全 Web 站点,是向每个用户签发一个用户名和密码,然后通过 SOAP 信息头和其他机制传递这些凭据。Cold Storage 示例使用自定义 SOAP 信息头和 HTTP 模块来提供身份验证。另一种方法是创建一个自定义登录 Web 服务。此处,调用者通过 SSL 等安全通道登录,并接收一个令牌以在调用 Web 服务上的其他方法时使用。

使用代码访问安全性

迄今为止,我们只讨论了唯一识别用户的方法。一旦我们知道用户是谁,我们就可以使用这些信息来授权用户访问 Web 服务内的一种或多种方法。示例用户是 sseely2\SampleGroup 组的成员。如果我想将对 WhoAmI Web 方法的访问权限限制在该组成员范围内,则可以应用 System.Security.Permissions.PrincipalPermissionAttribute 属性。具体来说,我将使用以下代码:

[WebMethod]
[PrincipalPermissionAttribute(SecurityAction.Demand,
Authenticated=true,
Name=@"sseely2\Example",
Role=@"sseely2\SampleGroup")]
public string WhoAmI() {
return "作为以下用户运行: " +
Thread.CurrentPrincipal.Identity.Name;
}

上面的代码有点极端。它要求知道调用者的 ID,要求调用者属于 sseely2\SampleGroup 组并且调用者的名称为 sseely2\Example。更常见的情况是要求成员属于某个特定组。这种技术提供了一种准予或拒绝访问特定 Web 方法的简单方法。使用代码访问安全性 - 当保护 .asmx 级的访问时,使用访问控制列表是不够的。   互操作性

如果在前面关于安全保护机制的论述中我没有提到互操作性的话,可能是我疏忽了。如果您想使用非 Microsoft 工具包来访问您的 Web 服务,那么,最具互操作性且经过良好测试的安全机制是使用基本身份验证来识别调用者和 SSL 的身份以加密通道。将此机制与集成 Windows 身份验证配合使用时,您需要向 Web 服务器用户或相应的 Windows 域控制器添加用户名和密码。原因很简单:许多 Web 服务堆栈不包括理解如何处理简要身份验证的 HTTP 部分。许多情况下,SSL/SOAP 组合可能不支持发送客户端 X.509 证书。

小结
  
您可以结合使用 IIS 和 ASP.NET 中的功能来确保 Web 服务的安全。ASP.NET Web 服务使用一个凭据式高速缓存来响应各种类型的身份验证请求。基本/简要身份验证和 SSL 都具有相同的缺点:

它们要求在安全地发送消息之前在 SOAP 消息发送者和接收者之间交换消息。此握手机制会限制 SOAP 消息传输的速度。提高速度正是 WS-Security 规范的动机之一。WS-Security 放弃了以消息为中心的安全保护模式的传输协议技术。在 WS-Security 被广泛理解和部署之前,基于 HTTP 的安全机制是保证 Web 服务安全的最好方法。

相关推荐