您的位置:首页 > 其它

WCF 项目应用连载[10] - 安全 X_509证书

2013-07-18 19:15 507 查看
有关WCF的安全问题 - Background -

___________________________________________________________________________________________________

Litelog工程至今我们还没有讨论安全,即服务端与客户端消息传输安全,客户端向服务端传递消息或服务端向客户端传递消息是否会别被劫持或是篡改?

这节我们将一个简单的x.509证书在Lig工程中的应用来说明WCF中传输层安全。

Artech在《WCF全面解析》一书中对分布式应用中的传输安全隐患做了一个总结:

1)消息篡改

2)敏感信息泄漏

3)钓鱼攻击

4)重放攻击

这意味着,所有分布式应用的程序都存在这几个问题。我们有必要考虑我们开发的分布式应用存在的这几个安全隐患。

显然,对于商用的服务器来说,除了提供服务本身,安全也是必要考虑的因素。


我们每天都在用Google与Baidu搜索服务,你可曾想象,他们除每天为数以亿计的用户提供正常的搜索服务,同时,他们的服务器可能每天都在面对大量来自网络上不同形式非正常访问与攻击,如果没有可靠的安全机制对服务资源的访问作必要的限制,我们很难想象,在这个互联网上,运行如此高访问量的Web服务器不想崩溃都难。

不过,对我们构建在WCF上的分布式应用而言,.net平台中的WCF已经为我们实现并提供了一系列功能齐全的安全策略,这些安全策略基本满足了我们最常用的开发需求,我们只需要要根据WCF中现有的安全策略定制我们自己的WCF服务即可。

10.1 传输安全模式

___________________________________________________________________________________________________

WCF传输安全模式主要分:Transport安全与Message安全

WCF传输安全主要涉及到认证、消息一致性与机密性三个主题,对应的安全策略有数字证书、数字签名与消息加密

本节的X.509证书属于WCF服务端或客户端标识自己身份证书,我们通过WCF服务认证或WCF客户端证实现在WCF服务端与WCF客户端进行安全的消息传输。

本节的示例为服务认证。

10.1.1 Transport安全

___________________________________________________________________________________________________

Transport安全建立在tcp传输层协议上,WCF采用一种安全的tcp传输通道对信息加密,提供信息传输点对点的安全。

这意味着如果网络传输中存在中间路由,Transport安全基于传输层信道提供的安全保障将不复存在。我们就得用Message安全。。。

10.1.2 Message安全

___________________________________________________________________________________________________

Message安全则针对消息本身进行加密,提供端到端的安全。

10.2 服务认证与客户端认证

___________________________________________________________________________________________________

WCF身份认证属于双向认证,含服务认证与客户端认证。WCF可以信任由可信任的根权威(VeriSign或Thwart)发布的服务证书(商用)。WCF使用
X509CertificateValidationMode. ChainTrust作为默认值。 这意味着,默认条件下,WCF需要使用这样的证书。

public sealed class X509CertificateRecipientClientCredential
{
public X509ServiceCertificateAuthentication Authentication { get; }
}
public class X509ServiceCertificateAuthentication
{
public X509CertificateValidationMode CertificateValidationMode { get; set; }
}


[align=left]10.2.1服务认证[/align]

[align=left]客户端对服务的认证称服务认证。即服务端提供证书,客户端在配置中显式指定证书名在客户端对证书进行校验。[/align]
[align=left]服务端则通过ServiceHostBase中的Credentials属性指定。在配置中,我们在Binding中指定一个属性Security来进行WCF通道传输的安全设置,并通过WCF服务行为来指定WCF安全传输所采用的证书信息(这儿指X.509证书)[/align]

public abstract class ServiceHostBase
public ServiceCredentials Credentials { get; }
<bindings>
<netTcpBinding>
<binding name="ligTcpBinding" closeTimeout="00:02:00" openTimeout="00:02:00" sendTimeout="00:10:00" receiveTimeout="24.00:00:00"
maxConnections="50" maxBufferPoolSize="40960000" maxBufferSize="10240000" maxReceivedMessageSize="10240000">
<reliableSession enabled = "false"  inactivityTimeout="10:00:00" />
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</netTcpBinding>
</bindings>


服务的服务行为(后面会提供完整的配置说明这些配置信息间的关系)

<behavior name="serviceCertificateBehavior">
<serviceCredentials>
<serviceCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" findValue="vivitue" />
</serviceCredentials>
</behavior>


[align=left]10.2.1客户端认证[/align]
——————————————————————————————————————————————————————————————

[align=left]服务端对客户端的认证称客户端认证。即客户端提供证书,在服务端进行证书校验。[/align]
[align=left]客户端通过ChannelFactory中的Credentials指定。[/align]

public abstract class ChannelFactory
public ClientCredentials Credentials { get; }


服务认证与客户端认证都可以通编程或配置方式指定

10.3 Lig系统服务端的X.509证书

这儿,我们构建一个服务认证。

10.3.1 MakeCert测试证书生成工具

——————————————————————————————————————————————————————————————

当然,作为普通的开发者基本不会购买VeriSign或Thwart这些组织颁发的商用证书。而Microsoft为开发者提供了一种生成X.509测试证书的工具

MakeCert.exe

借助该工具,通过命令行方式可以生成供开发者测试使用的证书。而本节内容在Lig系统中使用的证书由MakeCert工具生成。

但是,由MakeCert工具生成的证书有2个问题:

1) MakeCert生成的证书不能成为受信任的CA(Certification Authorities)

2) WCF客户端不能采用WCF的默认认证模式:X509CertificateValidationMode. ChainTrust。

这意味着

MakeCert生成的证书对服务端与客户端的配置有一定的限制,在服务认证中,我们需要在客户端配置中显式修改终节点行为为X509CertificateValidationMode.None

由于WCF采用X509CertificateValidationMode. ChainTrust作为客户端默认证书模式,我们通过配置修改了客户端默认证书模式,同时还要求终结点地址的DNS值与服务证书名相一致。

所以,当我们使用MakeCert工具生成服务端测试证书时,除Binding中显式指定安全属性与服务一样外,还需要在客户端配置中显式指定WCF客户端终节点身份地址(DNS)配置为测试证书名:

<endpoint name="Lig.vivitue.Contract.Services.LigAgent" behaviorConfiguration="IgoreSvcCertValidation"
address="net.tcp://127.0.0.1:6023/Lig.vivitue.Contract.Services.LigAgent"
contract="Lig.vivitue.Contract.Services.ILigAgent"
binding="netTcpBinding" bindingConfiguration="ligTcpBinding">
<identity>
<dns value="vivitue" />
</identity>
</endpoint>


对Lig系统来说,binding采用NetTcpBinding,传输模式使用Transport,同时采用了非Windows认证,底层主要基于TLS/SSL实现,对Lig服务端将选一个X.509证书作为服务凭证。

10.3.2 创建X.509证书

——————————————————————————————————————————————————————————————

我们可以通过如下两个命令创建一个名为vivitue的X.509证书。

1) 调出控制台,进入MakeCert.exe工具所在目录 (或用VS自带的控制台工具直接输入命令也行)

此处我们采用VS2005自带的MakeCert工具。 (VS2008/VS2010都行。自我Search下MakeCert.exe文件一切都不是问题。)

其路径为: C:\Program Files\Microsoft Visual Studio 5\SDK\v2.0\Bin

2) 生成CA证书用于指定WCF服务证书的颁发者:

Makecert -n "CN=vivitueCA" -r -sv C:\vivitueCA.pvk C:\vivitueCA.cer

该命今将弹出2个对话框,要求用户输入密码用于生成私钥文件与证书文件。

一个vivitueCA.pvk包含私钥的文件,一个是证书文件vivitueCA.cer。这两个文件全存储于C盘根目录。



[align=left]3) 生成WCF服务证书:vivitue X.509证书[/align]

[align=left]Makecert -n "CN=vivitue" -icC:\vivitueCA.cer -iv C:\vivitueCA.pvk -sr LocalMachine -ss My -pe -sky exchange[/align]

[align=left]该命令将创建一个自签名的WCF服务证书,证书名为vivitue,并指定颁发者为vivitueCA.cer,同时指定颁发者私钥文件vivitueCA.pvk,该证书最终保存到本机的个人存储区。[/align]

[align=left](自行Google或Baidu下了解下Windows的个人存储区是个什么概念)[/align]



[align=left]4) Makecert命令解释[/align]

=================================================================

[align=left]-n 指定证书名称格式 -n "CN=yourcertificate name"[/align]

[align=left]-r 创建自签名证书[/align]
[align=left]-sv 指定证书.pvk私钥文件[/align]

[align=left]-ic 指定颁发者证书文件[/align]

[align=left]-iv 指定颁发者.pvk文件[/align]

[align=left]-sr 指定证书存储位置 (此处为本机)[/align]

[align=left]-ss 指定证书存储区域 (此处为本机的个人存储区)[/align]

[align=left]-pe 指定私钥可导出,将私钥包含在证书中[/align]

[align=left]-sky 指定证书密钥类型 (exchange或signature)[/align]

=================================================================

5) MakeCert工具的其它帮助

当然,你还可以通过如下命令查看MakeCert工具的其它命令帮助

[align=left]MakeCert -?[/align]
[align=left]MakeCert -![/align]



10.4 Lig系统服务端配置

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="Lig" value="viviute"/>
<add key="Ligger" value="define your own config"/>
</appSettings>
<connectionStrings>
<add name="DBHelper" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" providerName="System.Data.OleDb" />
</connectionStrings>
<system.serviceModel>
<bindings> <netTcpBinding> <binding name="ligTcpBinding" closeTimeout="00:02:00" openTimeout="00:02:00" sendTimeout="00:10:00" receiveTimeout="24.00:00:00" maxConnections="50" maxBufferPoolSize="40960000" maxBufferSize="10240000" maxReceivedMessageSize="10240000"> <reliableSession enabled = "false" inactivityTimeout="10:00:00" /> <security mode="Transport"> <transport clientCredentialType="None"/> </security> </binding> </netTcpBinding> </bindings>
<services>
<service behaviorConfiguration="serviceCertificateBehavior" name="Lig.vivitue.Contract.Services.LigAgent">
<endpoint address="net.tcp://127.0.0.1:6023/Lig.vivitue.Contract.Services.LigAgent"
binding="netTcpBinding" bindingConfiguration="ligTcpBinding"
contract="Lig.vivitue.Contract.Services.ILigAgent"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="serviceCertificateBehavior"> <serviceCredentials> <serviceCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" findValue="vivitue" /> </serviceCredentials> </behavior>
<behavior name="metaDataBehavior">
<serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:7023/Lig.vivitue.LigMetadata"/>
</behavior>
<behavior name="serializerBehavior">
<dataContractSerializer maxItemsInObjectGraph="200000"/>
</behavior>
<behavior name="throttlingBehavior">
<serviceThrottling maxConcurrentCalls="50" maxConcurrentInstances="200" maxConcurrentSessions="100" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>


10.5 Lig系统客户端配置

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="ligTcpBinding" closeTimeout="00:02:00" openTimeout="00:02:00" sendTimeout="00:10:00" receiveTimeout="24.00:00:00"
maxConnections="50" maxBufferPoolSize="409600000" maxBufferSize="102400000" maxReceivedMessageSize="102400000">
<reliableSession enabled = "false" inactivityTimeout="10:00:00" />
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint name="Lig.vivitue.Contract.Services.LigAgent" behaviorConfiguration="IgoreSvcCertValidation" address="net.tcp://127.0.0.1:6023/Lig.vivitue.Contract.Services.LigAgent" contract="Lig.vivitue.Contract.Services.ILigAgent" binding="netTcpBinding" bindingConfiguration="ligTcpBinding"> <identity> <dns value="vivitue" /> </identity> </endpoint>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="IgoreSvcCertValidation">
<clientCredentials>
<serviceCertificate>
<authentication certificateValidationMode="None"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>


参考引文:

[1] Artech.WCF全面解析[M].2012

[2] O'Reilly.WCF编程[M].2009

[3] Adnrew Trolesen.C#与.net3.5/4高级程序设计[M].2009/2013
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: