复习WCF(11)----- 安全概述

 

 

安全性概述

 

常见的安全威胁

1.观测网络流量以获取敏感信息。以在线银行为例,某个客户端请求将资金从一个账户转到另一个账户,一个恶意用户截取了此消息(具有账户和密码),随后盗取资金

2.欺诈性实体在客户端未发觉的情况下起服务作用。在此情况下,恶意用户(欺诈方)充当在线服务(做一个假的服务Host住客户的请求),从客户端截取消息以获取敏感信息,

然后欺诈方使用窃取的的数据盗取资金。此类攻击也称为“钓鱼攻击”

3.更改消息以获取与调用方所需的结果不同的结果(改掉消息继续传送到服务器)。例如,更改目标存款帐号以便将资金转入恶意账户中

4.黑客重放,恶意黑客重放同一订单。例如,一家网上书店收到数百张订单并将书籍发送给并未订购这些书籍的客户

5.使某项服务无法对客户端进行身份验证。在此情况下,服务无法确保相应人员执行该项事务

 

wcf如何来避免这些安全漏洞呢?

传输安全性可提供下列保障

1.服务终结点(响应方)身份验证  //验证服务 因为可能是个"假"服务

2.客户端主体(发起方)身份验证  //验证客户 看它是否有资格访问服务

3.消息完整性  //是否被破坏过

4.消息保密性  //加密

5.重放检测

 

- wcf是一个基于SOAP消息的分布式编程平台,因此保护客户端和服务之间的消息安全对于保护数据非常重要。(soap是明文的文本消息)

- wcf基于现有安全性基础结构和SOAP消息的经验证的安全标准提供可互操作的安全消息交换通用平台。(wcf既没有抛弃原有的一些安全性基础结构,又可以支持SOAP消息的安全标准)

- 现有的安全性基础结构有哪些呢?

        - 通常,Web服务部署都具有现成的安全性解决方案,例如,安全套接字层(SSL)或Kerberos协议。某些服务则利用已部署的安全性基础结构,例如,使用ActiveDirectory

    的Windows域,当评估和采用新服务时,通常需要这些现有技术集成。

        - wcf安全性与现有传输安全模型集成,并且可对基于SOAP消息安全的新传输安全模型使用现有基础结构

 

既然可以与现有的安全性基础结构集成,当然它就可以有很多现有的身份验证模型

- 任何通信安全模型的一个重要组成部分就是能够识别正在通信的实体并对其进行身份验证。这些通信中的实体使用“数字标识“或者凭据向通信对等方验证自己的身份。随着分布式

通信平台的发展,已实现多种不同的凭据身份验证和相关的安全模型

     - 在Internet中,通常使用用户名和密码标识用户

     - 在Intranet中,使用Kerberos域控制器备份用户和服务身份验证变得越来越普遍 (局域网没必要在多加用户名和密码来标识,可以直接用域的认证来实现安全)

     - 另个业务合作伙伴之间,证书可用于对合作伙伴的身份进行相互验证

- 因此,在Web服务的领域中,同样的服务可向内部企业客户公开,也可以向外部合作伙伴或Internet客户公开,重要的是基础结构可提供与这些现有安全身份验证模型的集成。

wcf支持多种凭据类型(身份验证模型)

     - 匿名调用方                 //不需要标识 谁都可以访问的服务

     - 用户名客户端凭据         //提供用户名密码

     - 证书客户端凭据           //提供一个证书

     - Windows(Kerberos协议(域) 和 NT LanMan[NTLM] )

 

WCF安全性功能划分 

- 传输安全性

        - 传输安全性包含3个主要功能:完整性、保密性和身份验证。完整性就是检测消息是否已被篡改的能力,保密性就是保证除预期接收方之外的其他人员都无法读取某个

    消息:可以通过加密实现。身份验证就是验证已声明标识的能力。将这三项功能结合在一起,有助于确保消息安全的从一方到另一方

- 访问控制

       - 访问控制也称为身份验证,身份验证使得不同的用户可以具有不同的数据查看权限

- 审核

       - 审核就是将安全事件记录到Windows事件日志中。可以记录与安全相关的事件,例如身份验证失败(或成功)

 

WCF传输安全的常见方案

1.使用Windows域确保传输安全 (局域网内)

2.使用UserName和Https确保传输安全

3.使用证书确保传输安全

传输安全模式 

Transport:传输安全模式

Message:消息安全模式

 

绑定支持的安全模式 

 

凭据和传输安全 

- 无论你用上述的哪种模式,都会涉及到凭据的提供。凭据是一些数据,用户证实已声明标识或功能。出示凭据的操作包括,同时出示数据和对数据的所有权证明

- 例如,WCF中支持的两种凭据类型

- 用户名

    - 用户名表示已声明的标识,密码标识所有权证明。这种情况下,受信任的颁发机构则是验证用户名和密码的系统(数据库+验证)

- (X.509)证书凭据

    - 在证书凭据中,主题名称、主题备用名称或证书中的特定字段可用于表示已声明标识或/功能。凭据中的数据所有权证明的建立,使用关联私钥生成签名实现的

 

传输安全模式(Transprot)的凭据类型   

消息安全模式(Message)的凭据类型 

 

 

理论完了 接下来看Demo

Demo1 TransportSecurity 传输安全:

项目结构图:

客户端是控制台应用程序

服务端是一个类库,将部署到IIS上

 

服务端代码 service.cs:

using System.ServiceModel;

namespace Service
{
    [ServiceContract]
    public interface ICalculator
    {
        [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);
    }

    public class CalculatorService : ICalculator
    {
        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;
        }
    }

}

很简单,就是加减陈楚而已

service.svc:

 <%@ ServiceHost Language="C#" Debug="true" Service="Service.CalculatorService" %>

Web.config:

 

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    
    <services>
      <service name="Service.CalculatorService" behaviorConfiguration="CalculatorServiceBehavior">
        <!--终结点指定了一个具体的wsHttpBinding的Binding : Binding1 -->
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="Binding1"  contract="Service.ICalculator" />

        <endpoint address="mex"
                  binding="mexHttpBinding"
                  contract="IMetadataExchange" />
      </service>
    </services>

    <bindings>
      <wsHttpBinding>
        <binding name="Binding1">
          <!--配置使用传输安全、还是消息安全、还是混合模式-->
          <!--现在指定的是传输安全,意思就是所有的安全性交由传输层来决定,传输层也就是我们的部署方,IIS-->
          <security mode="Transport">
            <transport clientCredentialType="None"/> <!--clientCredentialType:客户端的凭据信息。这些东西在上面的表格都有解释-->
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>

    <behaviors>
      <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior">
          <serviceMetadata httpGetEnabled="True"/>
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>

  </system.serviceModel>
</configuration>

 

 

 

接下来生成项目部署到IIS上 如图:

 

接下来打开IIS的SSL的支持 就是让IIS能够支持到这个安全套接字层 怎么打开呢?如图

然后点击确定 ,证书就已经创建好了(证书的期限默认是一年,可以双击证书从详细信息中看到)

我们所有在这IIS上部署的服务或是网站,都可以利用这个证书来进行安全套接字层的部署(所有这个IIS上面利用Https访问的数据交换都会使用到这个证书签名和加密)

接来下继续看图:

 

忽略的话就是又可以用Https访问 又可以用Http访问

都设置好了后 我们可以试着访问下,在浏览器输入地址 我的是:https://localhost/ServiceModelSamples/sercice.svc 效果如下:

我们这台IIS上的证书 不是经过第三方机构认证的,所以他会提出一个警示,浏览器不认识这个证书

没关系,我们点击"继续浏览此网站"就可以看到了

 

然后在客户端添加服务引用:(当然也可以使用svcutil生成代理类)

 

客户端Program.cs:

using System;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using Client.ServiceReference1;

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            PermissiveCertificatePolicy.Enact("CN=teddy-PC");

            CalculatorClient client = new CalculatorClient();

            double value1 = 100.00D;
            double value2 = 15.99D;
            double result = client.Add(value1, value2);
            Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);

            value1 = 145.00D;
            value2 = 76.54D;
            result = client.Subtract(value1, value2);
            Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result);

            value1 = 9.00D;
            value2 = 81.25D;
            result = client.Multiply(value1, value2);
            Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);

            value1 = 22.00D;
            value2 = 7.00D;
            result = client.Divide(value1, value2);
            Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);

            client.Close();

            Console.WriteLine();
            Console.WriteLine("Press <ENTER> to terminate client.");
            Console.ReadLine();
        }
    }

    /// <summary>
    /// 证书策略,需要找到这个证书,我们才认可这个服务是有效的服务端在承载的
    /// </summary>
    class PermissiveCertificatePolicy
    {
        string subjectName;
        static PermissiveCertificatePolicy currentPolicy;
        
        PermissiveCertificatePolicy(string subjectName)
        {
            this.subjectName = subjectName;
            ServicePointManager.ServerCertificateValidationCallback +=
                new System.Net.Security.RemoteCertificateValidationCallback(RemoteCertValidate);
        }

        public static void Enact(string subjectName)
        {
            currentPolicy = new PermissiveCertificatePolicy(subjectName);
        }

        bool RemoteCertValidate(object sender, X509Certificate cert, X509Chain chain, System.Net.Security.SslPolicyErrors error)
        {
            if (cert.Subject == subjectName)
            {
                return true;
            }

            return false;
        }
    }
}

 

其中CD=teddy-PC中的teddy-PC,对应证书的使用者

 

如果将CN=teddy-PC修改一下 比如teddy-PCxxxx  结果如下:

 

正常情况如下:

 

安全套接字层承载在IIS里面,我们通过HTTPS这样的协议进行访问

所有在客户端和服务之间的请求的消息和返回的消息,都是由我们服务器上的证书在保持着加密,机密性和完整性

服务器的身份验证,是通过客户端的代码实现的 PermissiveCertificatePolicy.Enact("CN=teddy-PC");这个函数

不推荐使用代码验证,当然也有配置文件的身份验证方式:就是告诉客户端要去访问的服务端必须有某个证书才是真正有效的

 

 

接下来看另外一个Demo

Demo2 MessageSecurity 消息安全:

项目结构图:

 

和上面的例子几乎一样  唯一不同的地方是服务多加了一个方法

Service.cs:

 

using System.ServiceModel;

namespace Service
{
    [ServiceContract]
    public interface ICalculator
    {
        [OperationContract]
        bool IsCallerAnonymous();
        [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);
    }


    public class CalculatorService : ICalculator
    {
        //是否为匿名访问
        public bool IsCallerAnonymous()
        {
            //直接通过安全上下文,可以知道客户端是否通过了证书验证或身份验证
            //如果没有,则是匿名的
            return ServiceSecurityContext.Current.IsAnonymous;
        }

        public double Add(double n1, double n2)
        {
            double result = n1 + n2;
            return result;
        }

        public double Subtract(double n1, double n2)
        {
            double result = n1 - n2;
            return result;
        }

        public double Multiply(double n1, double n2)
        {
            double result = n1 * n2;
            return result;
        }

        public double Divide(double n1, double n2)
        {
            double result = n1 / n2;
            return result;
        }
    }
}

 

 

 

service.svc是一样的

Web.config有一点小修改:

 

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <system.serviceModel>
    <services>
      <service
          name="Service.CalculatorService"
          behaviorConfiguration="CalculatorServiceBehavior">
        <endpoint address=""
                  binding="wsHttpBinding"
                  bindingConfiguration="Binding1"
                  contract="Service.ICalculator" />
        <endpoint address="mex"
                  binding="mexHttpBinding"
                  contract="IMetadataExchange" />
      </service>
    </services>

    <bindings>
      <wsHttpBinding>
        <binding name="Binding1">
          <!--配置使用传输安全、还是消息安全、还是混合模式-->
          <!--现在指定的是消息安全-->
          <security mode="Message">
            <message clientCredentialType="None"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>

    <behaviors>
      <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior">
          <!--服务凭据-->
          <serviceCredentials>
            <!--证书凭据-->
            <serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
          </serviceCredentials>
          
          <serviceMetadata httpGetEnabled="True"/>
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

</configuration>

 

 

 

接下来部署到IIS上  

注:有问题需要说一下  好多朋友都跟我反映过这个问题

就是部署到IIS上后(将bin文件夹和svc和web.config复制过去),出现如下错误

 

这是因为bin目录下的debug目录下才有DLL(bin\debug\xxx.dll),所以请把DLL复制到bin目录下(bin\xxx.dll)

 

然后生成开发时用的证书:

上面写错了 最后应该是TrustedPeople 写成了TrustedPerple

 

然后和上个示例一样,添加服务引用(也可以使用svcutil生成代理类)

客户端Program.cs(几乎没有修改,就只是去掉了证书验证的代码):

using System;
using System.ServiceModel;

namespace Microsoft.ServiceModel.Samples
{

    class Client
    {
        static void Main()
        {

            CalculatorClient client = new CalculatorClient();

            //IsCallerAnonymous():是否为匿名访问
            Console.WriteLine("IsCallerAnonymous returned: {0}", client.IsCallerAnonymous());

            double value1 = 100.00D;
            double value2 = 15.99D;
            double result = client.Add(value1, value2);
            Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);

            value1 = 145.00D;
            value2 = 76.54D;
            result = client.Subtract(value1, value2);
            Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result);

            value1 = 9.00D;
            value2 = 81.25D;
            result = client.Multiply(value1, value2);
            Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);

            value1 = 22.00D;
            value2 = 7.00D;
            result = client.Divide(value1, value2);
            Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);

            client.Close();

            Console.WriteLine();
            Console.WriteLine("Press <ENTER> to terminate client.");
            Console.ReadLine();
        }
    }
}

 

 

还可以通过修改配置文件的clientCredentialType实现不同的效果

 

posted @ 2013-03-16 13:14  韬韬韬你羞得无礼  Views(271)  Comments(0)    收藏  举报