有关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; }
}
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>
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>
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盘根目录。
=================================================================
=================================================================
5) MakeCert工具的其它帮助
当然,你还可以通过如下命令查看MakeCert工具的其它命令帮助
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