安全性概述
常见的安全威胁:
1) 观测网络流量以获取敏感信息。以在线银行为列,某个客户端请求将资金从一个账户转账到另一个账户。一个恶意用户截获了此消息(具有账号和密码),随后从盗用的账户将资金转出。
2) 欺诈性实体在客户端未发觉的情况下其服务的作用。在此情况下,恶意用户(欺诈方)充当在线服务,从客户端截获消息以获取敏感消息。然后,欺诈方使用窃取的数据将资金从盗用的账户转出。此类攻击也称为“钓鱼攻击”。
3) 更改消息以获取与调用方所需的结果不同的结果。例如,更改用于存款的账号以便将资金转移到恶意账户。
4) 黑客重放,恶意黑客重放同一采购订单。例如,一家网上书店收到数百张订单并将书籍发送给未订购这些书籍的客户。
5) 使某项服务无法对客户端进行身份验证。在此情况下,服务无法确保相应人员执行该项事务。
传输安全性可提供下列保障:
1) 服务终结点(响应方)身份验证
2) 客户端主体(发起方)身份验证
3) 消息完整性
4) 消息保密性
5) 重放检测
WCF是一个基于SOAP消息的分布式编程平台,因此保护客户端的服务之间的消息安全对于保护数据非常重要。
WCF基于现有安全性基础架构和SOAP消息的经验证的安全标准提供可互操作的安全消息交换通用平台。
与现有的安全性基础结构集成:
通常,Web服务部署都具有现成的安全性解决方案,例如,安全套接字层(SSL)或Kerberos协议。某些服务则利用已部署的安全性基础结构,例如,使用Active Director的WIndows域。当评估和采用新服务时,通常需要与这些现有技术集成。
WCF安全性与现有传输安全模型集成,并且可对基于SOAP消息安全的新传输安全模型使用现有的基础结构。
与现有身份验证模型集成
任何通信安全模型的一个重要组成部分就是能够识别正在通信的实体并对其进行身份验证。这些通信中的实体使用“数字标识”或凭据向通信对等方验证自己的身份。随着分布式通信平台的发展,以实现多种不同的凭据身份验证和相关的安全模型。
1) 在Internet中,通常使用用户名和密码标识用户。
2) 在Intranet中,使用Kerberos域控制器备份用户和服务身份验证变得越来越普遍。
3) 在业务合作伙伴之间,证书可用于对合作伙伴的身份进行相互验证。
因此,在Web服务领域中,同样的服务可向内部企业客户公开,也可想外部合作伙伴或Internet客户公开,重要的是基础结构可提供与这些现有安全身份验证模型的集成。WCF安全性支持多种凭据类型(身份验证模型),其中包括:
1) 匿名调用方。
2) 用户名客户端凭据。
3) 证书客户端凭据。
4) Windows(Kerberos协议和NT LanMan[NTLM])
WCF安全性的功能划分:
1) 传输安全性:
传输安全性包括三项主要安全功能:完整性、保密性和身份验证。完整性就是检测消息是否已被串改的能力。机密性就是保证除预期接收方之外的其他人员都无法读取某个消息;这可以通过加密技术实现。身份验证就是验证已声明标识的能力。将这三项功能结合在一起,有助于确保消息安全地从一个点到达另一个点。
2) 访问控制:
访问控制也成为身份验证。身份验证使得不同的用户可以具有不同的数据查看权限。
3) 审核:
审核就是将安全事件记录到Windows事件日志中。可以记录与安全相关的事件,例如身份验证失败(或成功)。
传输安全性
三项功能——完整性、保密性和身份验证——合称为传输安全:
使用WCF传输安全的常见方案包括:
1) 使用Windows确保传输安全:
WCF客户端和服务部署在Windows域(或WIndows目录林)中。
2) 使用Username和Https确保传输安全:
客户端凭据根据数据库(其中的内容为用户名/密码对)进行身份验证。服务是用受信任的安全套接字层(SSL)证书部署在一个HTTPS地址的。由于消息是通过Internet传输的,因此,客户端和服务需要相互进行身份验证,并且必须在传输过程中保持消息的保密性和完整性。
3) 使用证书确保传输安全:
客户端和服务都具有可用于确保消息安全的证书。客户端和服务通过Internet进行相互通信,执行要求消息完整性、保密性和相互身份验证的重要事务。
传输安全模式
绑定支持的安全模式:
凭据
传输安全示例(Transport)DEMO
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace Video14.Demo1.TransportSecurity
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "ICalculatorService" in both code and config file together.
[ServiceContract]
public interface ICalculatorService
{
[OperationContract]
double Add(double n1, double n2);
[OperationContract]
double Subtract(double n1, double n2);
[OperationContract]
double Multiply(double n1, double n2);
[OperationContract]
double Divide(double n1, double n2);
}
}
2) 实现该服务类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace Video14.Demo1.TransportSecurity
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "CalculatorService" in code, svc and config file together.
public class CalculatorService : ICalculatorService
{
public double Add(double n1, double n2)
{
return n1 + n2;
}
public double Subtract(double n1, double n2)
{
return n1 - n2;
}
public double Multiply(double n1, double n2)
{
return n1 * n2;
}
public double Divide(double n1, double n2)
{
return n1 / n2;
}
}
}
3) 配置配置文件,在配置文件里指定安全模式为传输安全模式:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="Video14.Demo1.TransportSecurity.CalculatorService" behaviorConfiguration="CalculatorServiceBehavior">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="Binding1" contract="Video14.Demo1.TransportSecurity.ICalculatorService"/>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="Binding1">
<!--指定在wsHttpBinding基础上使用安全模式为Transport的传输安全模式,所有的安全性都交由传输层来决定,传输层也就是部署方在IIS中进行配置-->
<security mode="Transport">
<!--客户端的凭据类型:客户端无需证明自己的身份-->
<transport clientCredentialType="None"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="CalculatorServiceBehavior">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
4) 编辑生成的bin及服务文件,部署到IIS上。
那么我们在IE上开打这个WCF服务的时候就会看到“HTTP 错误 403.7 - Forbidden您尝试访问的页面要求您的浏览器具有该 Web 服务器可识别的安全套接字层(SSL)客户证书”
12) 添加一个客户端程序Client,然后使用SVCUTIL控制台程序生成WCF服务的客户端代理类及配置文件(如果生成的时候有问题请参照:http://blog.youkuaiyun.com/eric_k1m/article/details/13770043),然后添加到该项目中。在Main方法中进行测试:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Client.ServiceReference1;
using System.Net;
using System.Security.Cryptography.X509Certificates;
namespace Client
{
class Program
{
static void Main(string[] args)
{
// WARNING: This code is only needed for test certificates such as those created by makecert. It is
// not recommended for production code.
//证书策略,需要找到CN=Eric-PC.TYCOFS.COM的证书,就相当于认可这个服务,然后才能进行方法的调用
PermissiveCertificatePolicy.Enact("CN=Eric-PC.TYCOFS.COM");
// Create a client with given client endpoint configuration
CalculatorServiceClient client = new CalculatorServiceClient();
// Call the Add service operation.
double value1 = 100.00D;
double value2 = 15.99D;
double result = client.Add(value1, value2);
Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);
// Call the Subtract service operation.
value1 = 145.00D;
value2 = 76.54D;
result = client.Subtract(value1, value2);
Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result);
// Call the Multiply service operation.
value1 = 9.00D;
value2 = 81.25D;
result = client.Multiply(value1, value2);
Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);
// Call the Divide service operation.
value1 = 22.00D;
value2 = 7.00D;
result = client.Divide(value1, value2);
Console.WriteLine("Divide({0},{1}) = {2}