`
阅读更多
webservices

http://extjsextendercontrol.codeplex.com/SourceControl/ListDownloadableCommits.aspx

http://www.yaosansi.com/post/551.html

http://blog.csdn.net/jim_yeejee/

http://www.infoq.com/cn/interviews/fengdahui-database-architecture

http://www.dbanotes.net/

作者Blog:http://blog.csdn.net/Eastunfail/


http://dev.csdn.net/develop/article/43/43345.shtm  
http://dev.csdn.net/develop/article/54/54503.shtm

http://topic.csdn.net/t/20041208/10/3625223.html


摘要:
如何使用支持WS安全规范的WSE(Microsoft Web Services Enhancements)使加密SOAP能够跨越标准HTTP呢?讲述了SOAP报文加密是如何进行,在WS安全和XML加密规范中又是如何定义的。
目录:
? 介绍WSE
? WSE的安全特性
? 加密SOAP报文
? WSE对加密的支持
? 配置WSE
? SOAP报文的对称加密算法
? 使用X.509证书来加密SOAP报文
? 选择报文的节点(组成部分)来加密
? 局限性和协作性细节
? 结论
WSE介绍
为了使Web 服务在企业内部运行得更好,新一代的Web 服务规范被提出来.建议应该改善对Web 服务很重要的方面如安全,可靠报文,发送附件对地区间的协调性.为了支持这些提议的标准,ms发布了WSE1.0 sp1,它包含了一系列的类来支持这些新的协议,如基于Microsoft的asp.net宿主的过滤器,拦截进入和发出的SOAP报文,拦截或者产生 SOAP头来支持需求的功能.WSE支持以下的规范:
? WS-安全和Web 服务安全补遗
? WS附件
? WS路由
? WS引用
WSE的安全特性
在 WSE运行时,由一系列过滤器产生和读取WS-security兼容的SOAP报头.当在一台支持WSE的Web服务器上接收到SOAP报文时,SOAP 报文经过一系列输入过滤器读取WS-*兼容的报头,如有必要修改它们,产生一系列相关程序对象.同样,输出的报文是经过一些列输出过滤器,序列化一定的报头如WSE对象定义的. 所有被WSE1.0 sp1所支持的Web服务安全特征由安全输入和输出过滤器通过SecurityInputFilter和SecurityOutputFilte对象来实现.它包含:数字签名,加密,签署和加密用户标识,签署和加密用x.509证书, 签署和加密用自定义2进制标识.
加密SOAP报文
用统一的格式来传输数据,使得有价值的数据容易被恶意用户访问,以至被拦截.使用SOAP和xml来传输数据不但数据有潜在的安全威胁,而且你Web 服务的内在工作方式有可能被发现,通过观察SOAP 报文本身带的 xml 语法.使用合适的加密算法,数据和信息接口可以得到完全的保护.加密是简单的使用一种可逆的算法使用特定的密钥对明文进行加密,使得数据如果不解密则无法阅读. 如今,互联网加密的最常见的形式引入了一种传输级的加密模式,例如IPSEC和SSL,在传输层加密 .有了一定的安全性,但是传输层加密影响性能,尤其是当只有SOAP报文的一部分需要加密时.而且传输层加密不允许报文安全的路由通过Web 服务作为中介.因为报文需要解密由媒介在她能以新的加密的流传送到最终接收者之前,
Xml加密是如何工作的
Xml 加密协议指定了SOAP报文的部分或者全部可以被加密.当使用xml加密时,将针对xml文档的部分进行加密,加密后的内容在EncryptedData 节点内部.WS安全是基于 xml加密的,充分保证了使用xml加密来加密SOAP 报文时, EncryptedData 是security头部节点元素的引用.如果在SOAP报文的主体中有多个节点被加密时,每个节点参考自每个独立的且在ReferenceList 中的ReferenceData节点
对于一个EncryptedData 节点,一些密钥的信息可以在KeyInfo节点指定,加密的算法则在EncryptionMethod节点中指定,keyinfo节点按照xml签名规范来定义的.
一个加密后的SOAP 报文
下面的SOAP报文示例有一个payment节点,含有一些敏感的客户信息.

    引用
    <SOAP:Envelope SOAP:xmlsn="http://www.w3.org/2002/12/SOAP-envelope">
    <SOAP:Header>
    ...
    </SOAP:Header>
    <SOAP:Body>
    ...
    <x:Order Type="Purchase" x:xmlns="http://example.com/order">
    <x:Payment Type="CreditCard">
    <x:CreditCard Type="Visa">
    <x:CardNumber>123456789123456</CardNumber>
    <x:ExperationDate>1108</ExperationDate>
    </x:CreditCard>
    </x:Payment>
    ...
    </x:Order>
    ...
    </SOAP:Body>
    </SOAP:Envelope>



因为payment节点含有敏感的数据,所以它应该被加密.下面的例子显示了相同的信息,但是payment节点被 EncryptedData节点代替了.EncryptedData节点内含有对payment 节点内部内容加密后的密文. EncryptedData节点是参考自security头中的DataReference 节点的

    引用
    <SOAP:Envelope SOAP:xmlsn="http://www.w3.org/2002/12/SOAP-envelope"
    xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"
    xmlns:xsig="http://www.w3.org/2000/09/xmldsig#"
    xmlns:WSse="http://schemas.xmlSOAP.org/WS/2002/04/secext">
    <SOAP:Header>
    <WSse:Security>
    <xenc:ReferenceList>
    <xenc:DataReference URI="#OrderID"/>
    </xenc:ReferenceList>
    </WSse:Security> ...
    </SOAP:Header>
    <SOAP:Body>
    ...
    <x:Order Type="Purchase" x:xmlns="http://example.com/order">
    <xenc:EncryptedData Id="OrderId">
    <xenc:EncryptionMethod
    Algorithm= "http://www.w3.org/2001/04/xmlenc#tripledes-cbc"
    <xsig:KeyInfo>
    <xsig:KeyName>My Symmetric Key</xsig:KeyName>
    </xsig:KeyInfo>
    <xenc:CipherData>
    <xenc:CipherValue>...</CipherValue>
    </xenc:CipherData>
    </xenc:EncryptedData>
    ...
    </x:Order>
    ...
    </SOAP:Body>
    </SOAP:Envelope>




当然,在这个例子中,你可以用数字签名来签署该报文,来防止怀有恶意的人来窜改数据,或者用时间戳或者其他唯一的标识来判断信息是否受到攻击.
加密的种类
对称加密和不对成加密
加密得算法可以分为对称加密和不对称加密.在对称加密算法中,一个密钥被用来进行信息交换得两方共享.发送方利用私钥得拷贝来加密数据.在接收方,利用同样得私钥的拷贝来解密数据.绝大多数得加密,如基于共享密码和共享安全标识都是对成加密得例子.
在这种类型的系统中,一个中心的服务器分发共享的密钥给需要安全交互的使用者.对称加密的缺点是共享密钥的管理,分发和保护它们的安全性,特别是在象internet这样的公网上.
为了克服在公共网络中管理密钥的的难度,使用成对的密钥来取代单一的密钥.在不对成加密算法中,双方都互相拥有一个私钥和一个密钥.
公钥是利用一种不可逆的方法对私钥进行操作后产生的,因此一旦两者中的一种用来加密数据,另外一种就可以用来解密.另外,不可由公钥来推测出私钥,而且只有用私钥来解密用公钥加密的数据.当发送异步加密的报文时,发送者利用接收者的公钥加密报文,确保只有接收者可以利用他的私钥来解密报文.如果你用另外一种方式来处理,任何人都可利用可利用的公钥来解密报文.不对称加密是PKI的基础,pki是x.509安全标准的基础.不对成加密算法是一种典型基于对大数处理的算法,如指数合对数运算.它比对成加密算法需要更多的cpu时间来进行加密和解密.,因为这个原因,不对成加密经常用来安全的传送一个对称的”会话”密钥,用来加密交互的剩余部分,这也只是在信息交换的持续周期内有效.
因为公钥可以很容易的获得,使用公钥进行加密减轻了分发和管理密钥的难度.不幸的是,这种方便性的代价是不对成加密算法通常比对成加密算法慢几个数量级.由于此,不对称加密方法只用来处理比较小的数据.例如安全密钥和标识以及数字签名.
WSE对加密的支持
WSE支持对SOAP 报文的部分加密.对称加密使用一个共享的密钥,不对称加密支持使用x.509证书.当使用WSE来加密SOAP报文时,整个body节点的内容被加密,除非明确指定不要加密.下面举了2个例子,一个加密这个主体部分,一个加密部分.
WSE运行时库实现了所有的WS-security.在SecurityInputFilter 和SecurityOutputFilter 类中SecurityOutputFilter 类中.前者通过查找Security节点在一个
进入的SOAP报文中,如果该节点存在.它创建了一个代表任意安全标记和加密密钥,解密节点,验证任何数字签名的对象.对于一个进入的报文,任何任何安全的节点都剋通过报文产生的SOAPcontext对象的安全属性进行访问.相反的, SecurityOutputFilter为进出报文实施加密和签名的操作,附带任何特定的安全标记或者加密密钥.安全措施,比如添加标记,加密,或者签署进出报文利用报文的SOAPContext.Security和SOAPContext.ExtendedSecurity属性, ExtendedSecurity只在需要创建安全报头时候使用Security属性只在为包含最终目的地时使用
配置WSE
尽管在安装时,WSE已经被安装到asp.net Web 服务器上,但是还需要一些额外的配置,如果需要那些asp.net应用使用安全支持的话.当创建完毕asp.net Web 服务后工程后,visual studio.net,引用Microsoft.Web.Services.dll 程序集需要加载到该项目中.你也需要对SOAPExtensionTypes节点添加一个新的SOAP扩展.这可在 Web.config文件中创建一个新的 add 节点.如下所示

    引用
    <configuration>
    <system.Web>
    ...
    <WebServices>
    <SOAPExtensionTypes>
    <add type=
    "Microsoft.Web.Services.WebServicesExtension,
    Microsoft.Web.Services,
    Version=1.0.0.0,
    Culture=neutral,
    PublicKeyToken=31bf3856ad364e35"
    priority="1" group="0" />
    </SOAPExtensionTypes>
    </WebServices>
    </system.Web>
    </configuration>



type属性的值必须不能包含任何间断或者额外的空格.这个例子为了可读性有额外的换行. 如果WebServices 和SOAPExtensionTypes 节点不存在,它们必须加到 Web.config文件里面.一种更容易的方法是完全WSE配置工具.一种visual studio的插件,使用它您可以非常容易的配置使用WSE的Web service 项目.当然还有一下其他相关的配置必须手工配置.
当使用 WSE进行编程时,你需要添加一个Microsoft.Web.Services 和一个System.security名字空间的引用.在客户端和服务器端的工程中,如果既在客户请求和服务器回应中加密了.在客户部分你应该使用添加 Web引用工具为基于WSE的Web service工程产生Web service代理.
给SOAP报文进行对称加密
接下来,让我们再来看看如何用WSE来给SOAP报文使用对称密钥加密。下面的例子是基于一个启用WSE的Web服务的,这个Web服务将返回一个SOAP 回应报文,在该报文正文内包含了一些敏感数据。这么说,客户端给服务发送一个简单的Web服务请求,该请求将返回一个由三元 DES对称加密算法(使用了一个共享密钥和一个初始向量,IV)加密过的XML文档,当客户端收到了加密后的回应信息后,SecurityInputFilter将调用一个在客户端的解密密钥提供程序,来访问客户端上相同的共享密钥,以此来对报文体进行解密,这个解密密钥提供程序必须由你来编写,并且提供一个用于同步共享密钥的方法。这些例子假设双方都知道密钥,并且我们所要做的,仅仅是提供密钥的名字,以此作为一个暗示,给对方知道我们用的是哪个密钥加密的信息。
双方之间管理、同步和和对密钥保密的时候一定要多加小心。有个解决方案使用了一个分布式密钥机制,例如Kerberos。但从WSE的1.0版本开始,WSE就不再继续支持Kerberos了。
加密对外发送的报文
这里我简单描述下如何创建一个可以返回个被加密的XML文档的Web服务。第一步先用using指示符来添加必要的命名空间,如下:

    引用 using System.Web.Services;
    using Microsoft.Web.Services;
    using Microsoft.Web.Services.Security;
    using System.Security.Cryptography;
    using System.Security.Cryptography.Xml;
    using System.Xml;



GetXmlDocument方法使用了的.NET框架实现的三元DES算法,采用128位密钥和64位初始化向量(IV),能够生成对称密钥。这个密钥还将拥有一个名字,并被添加到应答报文的SoapContext元素上,之后被SecurityOutputFilter使用于加密简单的XML文档,这个方法最后将返回给客户端。更多关于.NET框架的加密技术,请看.NET框架开发者指南上的Cryptography Overview一文。

    引用
    //返回由三元DES对称算法加密后的数据
    [WebMethod (Description="返回一个由对称加密算法机密后的敏感XML文档", EnableSession=false)]

    public XmlDocument GetXmlDocument()
    {
    //创建一个用于返回的简单的XML文档
    XmlDocument myDoc = new XmlDocument();
    myDoc.InnerXml =
    "<EncryptedResponse>这里是敏感数据.</EncryptedResponse>";

    //得到对外发送的回应报文的SoapContext
    SoapContext myContext = HttpSoapContext.ResponseContext;

    //创建一个用于加密的对称密钥,由于密钥是对称的,这些相同的数据必须存在有需求的客户端上。

    //定义共享的16字节数组,用来表示128位密钥
    byte[] keyBytes = {48, 218, 89, 25, 222, 209, 227, 51, 50, 168, 146,
    188, 250, 166, 5, 206};

    //定义共享的8字节(64位)数组,也就是初始化向量(IV)
    byte[] ivBytes = {16, 143, 111, 77, 233, 137, 12, 72};

    //创建三元DES算法的新实例
    SymmetricAlgorithm mySymAlg = new TripleDESCryptoServiceProvider();

    //设置好密钥和IV
    mySymAlg.Key = keyBytes;
    mySymAlg.IV = ivBytes;


    //创建一个新的WSE对称加密密钥
    EncryptionKey myKey = new SymmetricEncryptionKey(mySymAlg);


    //给他取个名字?
    KeyInfoName myKeyName = new KeyInfoName();
    myKeyName.Value = "http://example.com/symmetrictestkey";
    myKey.KeyInfo.AddClause(myKeyName);


    //使用对称密钥来创建一个新的EncryptedData元素
    EncryptedData myEncData = new EncryptedData(myKey);


    //将EncryptedData元素添加到SOAP回应上,告诉过滤器用指定的密钥来加密信息正文

    myContext.Security.Elements.Add(myEncData);

    return myDoc;
    }



基于前面的方法,WSE管道产生了下面有相应的安全头信息,密文和密钥信息的回应报文:

    引用
    <?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Header>
    <wsu:Timestamp
    xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility">
    <wsu:Created>2003-02-11T02:07:23Z</wsu:Created>
    <wsu:Expires>2003-02-11T02:12:23Z</wsu:Expires>
    </wsu:Timestamp>
    <wsse:Security soap:mustUnderstand="1"
    xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/07/secext">
    <xenc:ReferenceList
    xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
    <xenc:DataReference URI=
    "#EncryptedContent-f50076e3-5aea-435e-8493-5d7860191411" />
    </xenc:ReferenceList>
    </wsse:Security>
    </soap:Header>
    <soap:Body xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility"
    wsu:Id="Id-d2f22e02-a052-4dcb-8fbc-8591a45b8a9f">
    <xenc:EncryptedData
    Id="EncryptedContent-f50076e3-5aea-435e-8493-5d7860191411"
    Type="http://www.w3.org/2001/04/xmlenc#Content"
    xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
    <xenc:EncryptionMethod
    Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
    <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
    <KeyName>http://example.com/symmetrictestkey</KeyName>
    </KeyInfo>
    <xenc:CipherData>
    <xenc:CipherValue>0T5ThoGg14JmElph...qDJS=</xenc:CipherValue>
    </xenc:CipherData>
    </xenc:EncryptedData>
    </soap:Body>
    </soap:Envelope>




注意,在报文正文中ReferenceList元素包含了一个到EncryptedData元素的引用,这个元素包含了密钥的名字,使用的加密算法和一个数据的密文形式。
解密收到的报文
不管是在客户端还是在服务器端,WSE总是在SecurityInputFilter实现报文解密的,由于对称加密需要由公共密钥派生出来的加密密钥,你需要创建一个SecurityInputFilter能够调用的方法来得到这个对称密钥,然后你就能使用包含在EncryptedData中的密钥和算法信息来帮你找到正确的共享密钥和加密算法了。这个方法必须实现在从 Microsoft.Web.Services.Security.IDecryptionKeyProvider派生出来的类中。在我的例子中,DecryptionKeyProvider.GetDecryptionKey方法返回了对称密钥,如下:

    引用

    public DecryptionKey GetDecryptionKey(string encAlgorithmUri,
    KeyInfo keyInfo)
    {

    //重新创造同样的用于表示128位密钥的16个字节
    byte[] keyBytes = {48, 218, 89, 25, 222, 209, 227, 51, 50, 168, 146,
    188, 250, 166, 5, 206};


    //重新创造表示初始化向量的8个字节(64位)
    byte[] ivBytes = {16, 143, 111, 77, 233, 137, 12, 72};

    SymmetricAlgorithm mySymAlg = new TripleDESCryptoServiceProvider();
    mySymAlg.Key = keyBytes;
    mySymAlg.IV = ivBytes;

    //重新创建对称加密密钥
    DecryptionKey myKey = new SymmetricDecryptionKey(mySymAlg);

    return myKey;
    }



即便在我的方法中并没使用他们,WSE还是要把KeyInfo元素和加密算法的URI传递给这个方法的,决定使用哪一个共享密钥或者加密算法来产生对称密钥

为了让SecurityInputFilter能够访问到GetDecryptionKey方法,下面的配置信息必须加入到应用程序的配置文件中(也就是 app.config 文件)

    引用

    <configuration>
    ...
    <microsoft.web.services>
    <security>
    <decryptionKeyProvider
    type="MyClient Assembly.DecryptionKeyProvider,
    MyClientAssembly" />
    </security>



type 属性不能有任何过多的空格或者任何换行。他们只包含上面的内容以增强可读性,这个也可一用WSE设置工具来修改。一旦 DecryptionKeyProvider类被添加到客户端而且WSE安全支持已经配置好了,WSE将自动拦截加密数据,一个基于标准的Web服务的2 次开发平台程序,就可以让你随心所欲的给客户端编程了。

使用 X.509 证书来给SOAP报文加密
正如我前面提到的,非对称操作有一定开销。当传输大量数据时,从性能上来说,用非对称算法来加密这些数据会显得不太实际,WSE就这个问题,实现了一种伪非对称性加密(pseudo-asymmetric encryption)。和非对称性加密的报文相比,WSE使用一个非对称性算法和X.509证书的一个公开备份,以此来加密对称密钥,而实际上这些被用来给报文加密。当收到报文后,SecurityInputFilter得到和X.509证书相关联的私有密钥,以此给对称密钥解密,然后用解密后的密钥给报文正文解密。为了能让这个例子能够正常工作,一个来自受信任的证书认证的X.509证书(支持加密),必须出现在客户机器上当前用户帐号的个人证书储藏室里面,这个证书的私有密钥也必须出现在本地机器在主管Web服务的服务器的帐号里。另外,CA证书链中的一个证书必须出现在客户端的受信任储存室里,那样WSE才知道可以信任接受到的X.509证书。
加密对外发送的报文
我已经修改了前面的 GetXmlDocument方法,让它可以使用由WSE实现的基于X.509非对称加密技术。加密回应报文,FindCertificateBySubjectString方法可以用来接收客户端证书的公开备份,一个来自本地机器账号的个人储存室给的客户端证书。这个证书然后被用来创建一个新的 X.509安全Token,这个Token将被加入到响应报文的SoapContext的安全Token集合里。另外,在对称加密例子中引用的命名空间,你应该再加一个using指示附来引用一个Microsoft.WebServices.Security.X509命名空间。 GetXmlDocument方法代码如下:

    引用 //创建一个用于返回的简单XML文档
    XmlDocument myDoc = new XmlDocument();
    myDoc.InnerXml =
    "<EncryptedResponse>This is sensitive data.</EncryptedResponse>";
    "<EncryptedResponse>这里是敏感数据.</EncryptedResponse>";

    //得到响应报文的SoapContext
    SoapContext myContext = HttpSoapContext.ResponseContext;

    //打开并读取本地机器帐号的个人证书储存室
    X509CertificateStore myStore =
    X509CertificateStore.LocalMachineStore(
    X509CertificateStore.MyStore);
    myStore.OpenRead();

    //查找所有名为”我的证书”的证书,然后将所有匹配的证书添加到证书集合中
    X509CertificateCollection myCerts =
    myStore.FindCertificateBySubjectString("My Certificate");
    X509Certificate myCert = null;

    //查找在集合中中的第一个证书
    if (myCerts.Count > 0)
    {
    myCert = myCerts[0];
    }

    //确定我们有一个可以用于加密的证书
    if (myCert == null || !myCert.SupportsDataEncryption)
    {
    throw new ApplicationException("Service is not able to
    encrypt the response");

    return null;
    }
    else
    {
    //使用有效的证书来创建一个安全Token
    X509SecurityToken myToken = new X509SecurityToken(myCert);
    //WSE将使用这个标记来加密报文正文的
    //WSE产生一个KeyInfo元素,用来请求客户端上曾用于给报文解密的证书

    EncryptedData myEncData = new EncryptedData(myToken);
    //将已加密数据元素添加到响应报文的SoapContext上
    myContext.Security.Elements.Add(myEncData);

    return myDoc;
    }



基于前面的方法,WSE管道产生了下面的有相应Security头、密文和密钥信息的元素:

    引用
    <?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Header>
    <wsu:Timestamp
    xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility">
    <wsu:Created>2003-02-11T01:34:01Z</wsu:Created>
    <wsu:Expires>2003-02-11T01:39:01Z</wsu:Expires>
    </wsu:Timestamp>
    <wsse:Security soap:mustUnderstand="1"
    xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/07/secext">
    <xenc:EncryptedKey
    Type="http://www.w3.org/2001/04/xmlenc#EncryptedKey"
    xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
    <xenc:EncryptionMethod
    Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
    <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
    <wsse:SecurityTokenReference>
    <wsse:KeyIdentifier ValueType="wsse:X509v3">
    YmlKVwXYD8vuGuYliuIYdEAQQPw=
    </wsse:KeyIdentifier>
    </wsse:SecurityTokenReference>
    </KeyInfo>
    <xenc:CipherData>
    <xenc:CipherValue>UJ64Addf3Fd59XsaQ=…</xenc:CipherValue>
    </xenc:CipherData>
    <xenc:ReferenceList>
    <xenc:DataReference URI=
    "#EncryptedContent-608eef8b-4104-4469-95b6-7cb4703cfa03" />
    </xenc:ReferenceList>
    </xenc:EncryptedKey>
    </wsse:Security>
    </soap:Header>
    <soap:Body xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility"
    wsu:Id="Id-70179c5b-4975-4932-9ecd-a58feb34b0d3">
    <xenc:EncryptedData
    Id="EncryptedContent-608eef8b-4104-4469-95b6-7cb4703cfa03"
    Type="http://www.w3.org/2001/04/xmlenc#Content"
    xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
    <xenc:EncryptionMethod
    Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
    <xenc:CipherData>
    <xenc:CipherValue>
    4o1b4befwBJu6tzuaygfrAaX0UGtaYKcw2klIbuZPjLi...z8i2ypHN4+w==
    </xenc:CipherValue>
    </xenc:CipherData>
    </xenc:EncryptedData>
    </soap:Body>
    </soap:Envelope>



注意在这个已加密的报文里面,由非对称加密过的EncryptedKey元素包含了用于给报文正文加密的对称加密密钥。 ReferenceList元素引用了报文正文的EncryptedData元素的Id属性。虽然我在我的例子中没这样做,标记这个消息以便能让容器验证发送者其实是个不错的想法。关于使用WSE来标记报文的详细信息,看WS-Security Authentication and Digital Signatures with Web Services Enhancements
给收到的报文解密
当收到一个由X.509证书加密后的报文后,SoapInputFilter会自动尝试使用用户密钥储存室的私有密钥来进行解密,当然,这个需要告诉WSE 运行时哪里可以找到这个证书的额外配置信息。这个信息由应用程序配置文件的Security元素所指定,这个例子在客户端上的应用程序配置文件是 App.config。对于 X.509加密,你只需要添加一个x509子节点,内容和下面一样就可以了

    引用
    <x509
    storeLocation="CurrentUser"
    verifyTrust="true"
    allowTestRoot="false" />




在我的例子中,我将x509节点的storeLocation属性设为CurrentUser,假设证书在当前用户的证书储存室里,当我使用了来自CA的受信任证书之后,我也将verifyTrust设为true了。这些属性还能够用WSE的设置工具来修改。利用这些信息,WSE能够得到报文中证书的私有密钥,还能用这个来给对称性会话密钥解密,解密后的内容到头来还要给报文正文解密。
选择用于解密的报文元素
当整个消息正文由默认设置给加密后,WSE能被用来给SOAP报文内的特定元素加密;唯一的问题是,在Security头元素那的元素不能被加密。你还可以加密嵌套的元素,
在这个例子服务中,我修改了GetXmlDocument方法用的X.509版本,用一个基于X.509的安全Token来同时给EncryptedSubResponse和它的EncryptedResponse父节点进行数字化加密,返回的XML文档如下:

    引用 <Response>
    <NotEncrypted>
    回应报文的这里没有必要被加密
    </NotEncrypted>
    <EncryptedResponse>
    <EncryptedSubResponse>
    这里是敏感数据.
    </EncryptedSubResponse>
    </EncryptedResponse>
    </Response>



为了加密一个元素,它需要一个wsu:Id属性,以便当XML被序列化后引用可以加到该节点上了。命名空间wsu被定义为:

    引用 xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility



为了完成这个,我将这个XML加到一个新的XML文档,然后通过.NET框架支持的Microsoft XML文档对象模型(DOM)给它添加一个Id属性,此外还需要将配件System.Xml加入到工程引用里面,加上下面的话:

    引用
    using System.Xml;
    using System.Xml.Serialization;



当我将多个Id属性加到嵌套的元素上后,我由EncryptedSubResponse元素开始依次遍历到它的父节点EncryptedResponse,如下:

    引用
    string [] myId = {"Id:" + Guid.NewGuid(),"Id:" + Guid.NewGuid()};


    //创建一个用于返回XML的XML文档
    XmlDocument myDoc = new XmlDocument();
    myDoc.LoadXml("<Response>" +
    "<NotEncrypted>回应报文的这里没有必要加密" +
    "</NotEncrypted>" +
    "<EncryptedResponse>" +
    "<EncryptedSubResponse>" +
    "这里是敏感数据. " +
    "</EncryptedSubResponse>" +
    "</EncryptedResponse>" +
    "</Response>");

    //得到EncryptedSubResponse节点
    XmlNode = myDoc.FirstChild.LastChild.FirstChild;


    //向上遍历元素,添加两个Id属性
    //向上保证内部的多数元素可以优先被加密
    //否则我们会得到一个异常
    for (int i=0;i<myId.Length;i++)
    {

    //创建新的Id属性
    string wsu = "http://schemas.xmlsoap.org/ws/2002/07/utility";
    XmlNode myAttr = myDoc.CreateNode(XmlNodeType.Attribute, "wsu",
    "Id", wsu);
    myAttr.Value = myId[ i ];

    //将属性添加到文档
    root.Attributes.SetNamedItem(myAttr);
    root = root.ParentNode; // 移动到父节点
    }



假设我早就用我前面的逻辑得到了来自X.509证书的安全记号,我将这些引用添加到EncryptedData元素,如下:

    引用
    //循环遍历Id值,将其添加到新的EncryptedData元素上
    for (int i=0;i<myId.Length;i++)
    {
    //创建一个新的头,”#”是的前缀,用来保证相关的URI能够引用到头
    EncryptedData myEncHeader = new EncryptedData(myToken, "#"+myId[ i ]);
    //添加一个新的头到集合中
    myContext.Security.Elements.Add(myEncHeader);
    }
    //返回加密数据
    return myDoc;



下面是被WSE在运行时序列化后产生的报文加密后的结果

    引用
    <?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Header>
    <wsu:Timestamp
    xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility">
    <wsu:Created>2003-02-11T20:21:52Z</wsu:Created>
    <wsu:Expires>2003-02-11T20:26:52Z</wsu:Expires>
    </wsu:Timestamp>
    <wsse:Security soap:mustUnderstand="1"
    xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/07/secext">
    <xenc:EncryptedKey
    Type="http://www.w3.org/2001/04/xmlenc#EncryptedKey"
    xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
    <xenc:EncryptionMethod
    Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
    <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
    <wsse:SecurityTokenReference>
    <wsse:KeyIdentifier ValueType="wsse:X509v3">
    YmlKVwXYD8vuGuYliuIOXOY7ZYN9PwHbfAhCiYOV0aYdEAQQPw=
    </wsse:KeyIdentifier>
    </wsse:SecurityTokenReference>
    </KeyInfo>
    <xenc:CipherData>
    <xenc:CipherValue>
    UyKGBEXdY8lYSzqgdgxOXOY7ZYN9PwHbfAhCiYOV0...bwRnWk=
    </xenc:CipherValue>
    </xenc:CipherData>
    <xenc:ReferenceList>
    <xenc:DataReference URI=
    "#EncryptedContent-cf014249-0e2a-4f8b-9002-13a7de916be0" />
    </xenc:ReferenceList>
    </xenc:EncryptedKey>
    <xenc:EncryptedKey
    Type="http://www.w3.org/2001/04/xmlenc#EncryptedKey"
    xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
    <xenc:EncryptionMethod
    Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
    <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
    <wsse:SecurityTokenReference>
    <wsse:KeyIdentifier ValueType="wsse:X509v3">
    YmlKVwXYD8vuGuYliuIYdEAQQPw=
    </wsse:KeyIdentifier>
    </wsse:SecurityTokenReference>
    </KeyInfo>
    <xenc:CipherData>
    <xenc:CipherValue>
    In8Kf1cIdiJJJXCLZ+... wMqBEevXmzk=
    </xenc:CipherValue>
    </xenc:CipherData>
    <xenc:ReferenceList>
    <xenc:DataReference URI=
    "#EncryptedContent-0744279a-02bf-4ad1-998e-622208eded0e" />
    </xenc:ReferenceList>
    </xenc:EncryptedKey>
    </wsse:Security>
    </soap:Header>
    <soap:Body>
    <GetXmlDocumentResponse xmlns="http://example.com/dime/">
    <GetXmlDocumentResult>
    <Response>
    <NotEncrypted>
    This part of the response does not need encryption
    </NotEncrypted>
    <EncryptedResponse
    wsu:Id="Id:e5e8d792-abe7-4476-91d0-856fbdf4a958"
    xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility">
    <xenc:EncryptedData
    Id=
    "EncryptedContent-cf014249-0e2a-4f8b-9002-13a7de916be0"
    Type="http://www.w3.org/2001/04/xmlenc#Content"
    xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
    <xenc:EncryptionMethod
    Algorithm=
    "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
    <xenc:CipherData>
    <xenc:CipherValue>
    2MNHCkGVH/5jb0pF4pCh3u2VaUKsWSA...AfEvJZT=
    </xenc:CipherValue>
    </xenc:CipherData>
    </xenc:EncryptedData>
    </EncryptedResponse>
    </Response>
    </GetXmlDocumentResult>
    </GetXmlDocumentResponse>
    </soap:Body>
    </soap:Envelope>



注意,在这个加密后的报文里,这里有一个用于表示X.509证书的BinarySecurityToken元素,但有两个分开的 EncryptedKey元素,每个EncryptedData元素都被添加到SoapContext,在最外面的被加密的元素中(EncryptedResponse),你只能看到EncryptedData元素,当EncryptedResponse被加密后,表示 EncryptedSub元素的EncryptedData元素也随之转换为密文了。当这个报文在客户端被收到时,SecurityInputFilter使用来自记号的信息来得到曾给两个EncryptedKey元素解密过的私有密钥。







http://msdn.microsoft.com/zh-cn/library/aa302390.aspx


Web 服务安全性

发布日期 : 10/8/2004 | 更新日期 : 10/8/2004

浏览全部的安全性指导主题

Microsoft Corporation

本章内容

灵活开放标准的使用使得 Web 服务成为一种优秀的机制,可以通过 Web 服务将功能向客户端公开,以及用它来承载前端 Web 服务可以访问的中间层业务逻辑。然而,由于标准的局限性,以及需要支持各种客户端类型,从而使 Web 服务面临着安全方面的挑战。

本章介绍如何开发和应用身份验证、授权和安全通信技术来保护 ASP.NET Web 服务。本章首先简要介绍三种主要的 Web 服务安全模型–传输/平台、应用程序和消息级–,然后详细介绍实现适用于 ASP.NET Web 服务的可用选项及传输/平台级安全性。

目标

利用本章来:

    *

      保护您的 Web 服务。
    *

      实现平台/传输级安全性解决方案。
    *

      比较和对比平台/传输级安全性与消息级安全性。
    *

      标识和使用由 ASP.NET Web 服务提供的网关守卫。
    *

      将客户端凭证传递给需要身份验证的 Web 服务。
    *

      将原调用者标识从 Web 服务传递到下游系统。
    *

      设计适合于您的 Web 服务的身份验证、授权和安全通信解决方案。

适用于:

本模拟适用于以下产品和技术:

    *

      Microsoft® Windows® Server 2000 和 Windows Server™ 2003 操作系统
    *

      Microsoft Internet Information Services (IIS) 5.0 及更高版本
    *

      Microsoft Active Directory® 目录服务
    *

      Microsoft .NET Framework 1.0 版(带 service pack 2)及更高版本
    *

      Microsoft Visual C#® .NET 开发工具

如何使用本章

要想从本单元获得最大价值,您应该:

    *

      具备使用 Visual C# .NET 的编程经验。
    *

      具备开发和配置 ASP.NET Web 应用程序的经验。
    *

      具备配置 IIS 安全性、Windows 安全性和 Active Directory 的经验。 具备配置 Enterprise Services (COM+) 应用程序的经验。
    *

      阅读“Introduction”一章。它定义了身份验证、授权和安全通信对分布式 Web 应用程序的重要性。
    *

      阅读“Security Model for ASP.NET Applications”一章它概述了创建分布式 ASP.NET Web 应用程序所使用的体系结构和技术,并着重指出在该体系结构中的什么地方适用身份验证、授权和安全通信。
    *

      阅读“身份验证和授权”一章。它详细介绍了当您使用 ASP.NET Web 服务时,可用的身份验证和授权机制。
    *

      阅读“安全通信”一章。它介绍 SSl 和 IPSec,这两种通信安全性技术在客户端与 Web 服务之间进行通信时会经常用到。
    *

      阅读“ASP.NET 安全性”一章。它深入介绍与 ASP.NET 相关的安全性问题,其中大部分与 ASP.NET Web 服务有关。
    *

      阅读以下各章,它们介绍如何实现本章所讨论的许多技术:
          o

            “How To Create a Custom Account to run ASP.NET”
          o

            “How To Call a Web Service Using SSL”
          o

            “How To Use IPSec to Provide Secure Communication Between Two Servers”
          o

            “How To Implement Kerberos Delegation for Windows 2000”

本页内容

Web 服务安全性模型 Web 服务安全性模型
平台/传输安全性体系结构 平台/传输安全性体系结构
身份验证和授权策略 身份验证和授权策略
配置安全性 配置安全性
将身份验证的凭证传递给 Web 服务 将身份验证的凭证传递给 Web 服务
传送原调用者 传送原调用者
受信任的子系统 受信任的子系统
访问系统资源 访问系统资源
访问网络资源 访问网络资源
访问 COM 对象 访问 COM 对象
将客户端证书用于 Web 服务 将客户端证书用于 Web 服务
安全通信 安全通信
小结 小结
Web 服务安全性模型

可以在三个级别应用 Web 服务安全性:

    *

      平台/传输级(点对点)安全性
    *

      应用程序级(自定义)安全性
    *

      消息级(端对端)安全性

每一种方法都具有各自的优缺点,下面将详细阐述这些方法。选择哪一种方法在很大程度上取决于消息交换中涉及到的体系结构和平台的特点。

注本章着重介绍平台级和应用程序级的安全性。消息级安全性将在全局 XML Web 服务体系结构 (GXA) 提案中以及专门在 WS-Security 规范中进行介绍。在编写本指南时,Microsoft 刚刚发布了 Web 服务开发工具包的技术预览版本。它可用于开发符合 WS-Security 规范的消息级安全性解决方案。有关详细信息,请参阅 http://msdn.microsoft.com/webservices/building/wse/。
平台/传输级(点对点)安全性

两个终结点(Web 服务客户端和 Web 服务)之间的传输通道可用于提供点对点的安全性。图 1 阐释了这种情况。

f10sn01
图 1. 平台/传输级安全性

当您使用平台级安全性时(它假定在公司 Intranet 上安装了紧密集成的 Microsoft_ Windows_ 操作系统环境):

    *

      Web 服务器 (IIS) 提供基本、摘集成和证书身份验证。
    *

      ASP.NET Web 服务继承了某些 ASP.NET 身份验证和授权功能。
    *

      可以使用 SSL 和/或IPSec 提供消息完整性和机密性。

何时使用

传输级安全性模型简单明了,并且可用于许多(主要是基于 Intranet 的)方案;在这些方案中,可以严格控制传输机制和终结点配置。

传输级安全性的主要问题有:

    *

      安全性取决于基本平台、传输机制和安全服务提供程序(NTLM、Kerberos 等等)并且与它们紧密集成。
    *

      安全性是在点对点的基础上应用的,无法通过中间应用程序节点提供多个跃点和路由。

应用程序级安全性

通过使用这种方法,应用程序负责提供安全性并使用自定义的安全功能。例如:

    *

      应用程序可以使用自定义的 SOAP 标头传递用户凭证,以便根据每个 Web 服务请求对用户进行身份验证。常用的方法是在 SOAP 标头中传递票证(或者用户名或许可证)。
    *

      应用程序可以灵活地生成其包含角色的 IPrincipal 对象。该对象可以是自定义类或 .NET ¿ò¼Ü提供的 GenericPrincipal 类。
    *

      应用程序可以有选择地加密需要保密的内容,但是这需要使用安全密钥存储,并且开发人员必须了解相关加密 API 的知识。

另一种方法是使用 SSL 提供机密性和完整性,并将它与自定义的 SOAP 标头结合起来以执行身份验证。
何时使用

在以下时候使用此方法:

    *

      您想要利用在现有应用程序中使用的用户和角色的现有数据库架构。
    *

      您想要加密消息的一部分,而不是整个数据流。

消息级(端对端)安全性

这是一种灵活性最大而且功能最强的方法,GXA 提案(特别是在 WS-Security 规范中)使用的就是这种方法。图 2 阐释了消息级安全性。

f10sn02
图 2. 消息级安全性

WS-Security 规范说明了 SOAP 消息传递的增强功能,这些功能提供了消息完整性、消息机密性以及单次消息身份验证。

    *

      身份验证是由在 SOAP 标头中传递的安全性令牌提供的。 WS-Security 不要求使用任何特定类型的令牌。安全令牌可以包括 Kerberos 票证、X.509 证书或自定义的二进制令牌。
    *

      安全通信是通过数字签名提供的,以便确保消息的完整性,并使用 XML 加密以确保消息的机密性。

何时使用

可以使用 WS-Security 构建框架以便在异类 Web 服务环境中交换安全消息。它非常适合于不能直接控制终结点和中间应用程序节点配置的异类环境和方案。

消息级安全性:

    *

      可以不依赖于基本传输。
    *

      支持异类安全性体系结构。
    *

      提供端对端的安全性并通过中间应用程序节点提供消息路由。
    *

      支持多项加密技术。
    *

      支持不可否认性。

Web 服务开发工具包

Web 服务开发工具包提供管理安全性所需的 API 以及路由和消息级检索等其他服务。该工具包符合最新的 Web 服务标准(例如 WS-Security 规范),因此,它支持与采用相同规范的其他供应商之间的互操作性。
更多信息

    *

      有关 Web 服务开发工具包和 WS-Security 规范的最新消息,请参见 MSDN 中的“XML 开发人员中心”页面:http://msdn.microsoft.com/webservices/.
    *

      有关 GXA 的详细信息,请参见 MSDN 上的文章“Understanding GXA”。
    *

      有关该主题的讨论,请参考 MSDN 上的“GXA 互操作性新闻组”。

返回页首
平台/传输安全性体系结构

图 3 显示了 ASP.NET Web 服务平台安全性体系结构。

f10sn03
图 3. Web 服务安全性体系结构

图 3 阐释了 ASP.NET Web 服务提供的身份验证和授权机制。当客户端调用 Web 服务时,将按下列顺序激发身份验证和授权事件:

   1.

      接收到来自网络的 SOAP 请求。它是否包含身份验证凭证取决于所使用的身份验证类型。
   2.

      IIS 可以有选择地使用基本、摘要、集成(NTLM 或 Kerberos)或证书身份验证对调用者进行身份验证。在不能使用 IIS (Windows) 身份验证的异类环境中,可以将 IIS 配置为使用匿名身份验证。在这个方案中,可以使用消息级属性(例如,在 SOAP 标头中传递的票证)对客户端进行身份验证。
   3.

      IIS 也可以配置为只接受来自特定 IP 地址的客户端计算机的请求。
   4.

      IIS 将已验证的调用者的 Windows 访问令牌传递给ASP.NET (如果将 Web 服务配置为使用匿名身份验证,则它可能是匿名 Internet 用户的访问令牌)。
   5.

      ASP.NET 对该调用者进行身份验证。如果将 ASP.NET 配置为使用 Windows 身份验证,则此时不会进行任何其他的身份验证;IIS 对调用者进行身份验证。

      如果使用的是非 Windows 身份验证方法,则将 ASP.NET 身份验证模式设置为“无”以使用自定义身份验证。

      注Web 服务目前不支持表单和 Passport 身份验证。
   6.

      ASP.NET 通过使用 URL 授权和文件授权来授权访问所请求的 Web 服务(.asmx 文件),文件授权使用与 .asmx 文件关联的 NTFS 权限来确定是否将访问权限授予已验证身份的调用者。

      注只能将文件授权用于 Windows 身份验证。

      对于细分的授权,还可以使用 .NET 角色(以声明方式或编程方式)确保授权调用者访问所请求的 Web 方法。
   7.

      Web 服务中的代码可以使用特定标识来访问本地和/或远程资源。在默认情况下,ASP.NET Web 服务不执行任何模拟,因此,配置的 ASP.NET 进程帐户提供该标识。也可以选择原调用者的标识或已配置的服务标识。

网关守卫

ASP.NET Web 服务中的网关守卫是:

    *

      IIS
          o

            如果禁用 IIS 匿名身份验证,则 IIS 只允许来自已通过身份验证的用户的请求。
          o

            IP 地址限制

      可以将 IIS 配置为只允许来自具有特定 IP 地址的计算机的请求。
    *

      ASP.NET
          o

            文件授权 HTTP 模块(仅用于 Windows 身份验证)
          o

            URL 授权 HTTP 模块
    *

      主体权限要求和明确的角色检查

更多信息

    *

      有关网关守卫的详细信息,请参见“ASP.NET 安全性”一章中“ASP.NET 安全性体系结构”部分的“网关守卫”主题。
    *

      有关配置安全性的详细信息,请参见本章后面的“配置安全性”。

返回页首
身份验证和授权策略

本节介绍一组常用身份验证方案的可用授权选项(可进行配置和编程)。

下面概述了一些身份验证方案:

    *

      带模拟功能的 Windows 身份验证
    *

      不带模拟功能的 Windows 身份验证
    *

      使用固定标识的 Windows 身份验证

带模拟功能的Windows 身份验证

以下配置元素向您显示了如何明确启用 Web.config 或Machine.config 中的 Windows (IIS) 身份验证和模拟功能。

注 应根据 Web 服务的具体情况,在每个 Web 服务的 Web.config 文件中配置身份验证。

<authentication mode="Windows" />
<identity impersonate="true" />

在此配置中,Web 服务代码模拟已由 IIS 验证身份的调用者。要模拟原调用者,您必须在 IIS 中关闭匿名访问。借助于匿名访问,Web 服务代码可以模拟匿名 Internet 用户帐户(在默认情况下,该帐户为 IUSR_MACHINE)。
可配置的安全设置

当您将 Windows 身份验证和模拟功能一起使用时,就可以使用下列授权选项:

    *

      Windows 访问控制列表 (ACL)
          o

            Web 服务 (.asmx) 文件。文件授权使用原调用者的安全性上下文对请求的 ASP.NET 资源(包括 .asmx Web 服务文件)执行访问检查。必须至少授权原调用者读取 .asmx 文件的权限。
          o

            Web 服务访问的资源。Web 服务所访问的资源(文件、文件夹、注册表项和 Active Directory_ 目录服务对象等等)的 Windows ACL 必须包含一个访问控制项 (ACE),该访问控制项授予原调用者“读”权限(因为用于资源访问的 Web 服务线程正在模拟该调用者)。
    *

      URL 授权。这是在 Machine.config 和/或 Web.config 中配置的。在 Windows 身份验证中,用户名采用 DomainName\UserName 格式,并且角色与 Windows 组一一对应。

      <authorization>
          <deny user="DomainName\UserName" />
          <allow roles="DomainName\WindowsGroup" />
          </authorization>
         

编程安全性

编程安全性是指您的 Web 服务代码中的安全性检查。在您使用 Windows 身份验证和模拟功能时,可以使用下列程序安全设置选项:

    *

      主体权 限要求 命令性(嵌入方法的代码内)

          PrincipalPermission permCheck = new PrincipalPermission(
          null, @"DomainName\WindowsGroup");
          permCheck.Demand();
         

    *

      声明性(这些属性可以优先于 Web 方法或 Web 类)

      // Demand that the caller is a member of a specific role (for Windows
          // authentication this is the same as a Windows group)
          [PrincipalPermission(SecurityAction.Demand,
          Role=@"DomainName\WindowsGroup")]
          // Demand that the caller is a specific user
          [PrincipalPermission(SecurityAction.Demand,
          Name=@"DomainName\UserName")]
         

    *

      明确的角色检查。您可以使用 IPrincipal 接口执行角色检查。

      IPrincipal.IsInRole(@"DomainName\WindowsGroup");
         

何时使用

使用 Windows 身份验证和模拟的情况是:

    *

      Web 服务的客户端可以通过使用 Windows 帐户来标识,而 Windows 帐户则可以由服务器验证。
    *

      您需要通过 Web 服务将原调用者的安全性上下文传递到下一层。例如,传递到一组使用 Enterprise Services (COM+) 角色的服务组件,或传递到需要细化(每用户)授权的数据层。
    *

      您需要将原调用者的安全性上下文传递到下游各层以支持操作系统级审核。

重要 使用模拟功能可能会降低可扩展性,因为它会影响数据库连接池。作为一个替代方法,可以考虑使用受信任的子系统模型;在该模型中,Web 服务对调用者进行授权并使用固定标识来访问数据库。可以在应用程序级别上传递调用者标识;例如,使用存储过程参数来传递。
更多信息

    *

      有关 Windows 身份验证和模拟的详细信息,请参见“ASP.NET Security”一章。
    *

      有关 URL 授权的详细信息,请参见“ASP.NET Security”一章中的“URL 授权注意事项”。

不带模拟功能的 Windows 身份验证

下列配置显示了如何在 Web.config 中明确声明启用不带模拟功能的 Windows (IIS) 身份验证。

<authentication mode="Windows" />
<!-- The following setting is equivalent to having no identity element -->
<identity impersonate="false" />

可配置的安全性

当您使用不带模拟功能的 Windows 身份验证时,可以使用以下授权选项:

    *

      Windows ACL
          o

            Web 服务 (.asmx) 文件.文件授权使用原调用者对请求的 ASP.NET 资源(包括 .asmx Web 服务文件)执行访问检查。模拟不是必需选项。
          o

            应用程序访问的资源。应用程序所访问的资源(文件、文件夹、注册表项和 Active Directory 对象等)的 Windows ACL 必须包含一个 ACE,它授予 ASP.NET 进程标识(访问资源时 Web 服务线程所使用的默认标识)“读”权限。
    *

      URL 授权

      这是在Machine.config 和 Web.config 中配置的。在 Windows 身份验证中,用户名采用 DomainName\UserName 格式,并且角色与 Windows 组一一对应。

      <authorization>
          <deny user="DomainName\UserName" />
          <allow roles="DomainName\WindowsGroup" />
          </authorization>
         

编程安全性

编程安全性是指您的 Web 服务代码中的安全性检查。当您使用不带模拟功能的 Windows 身份验证时,可以使用下列编程安全性选项:

    *

      主体权限要求
          o

            命令性

                PrincipalPermission permCheck = new PrincipalPermission(
                    null, @"DomainName\WindowsGroup");
                    permCheck.Demand();
                   

          o

            声明性

            // Demand that the caller is a member of a specific role (for Windows
                    // authentication this is the same as a Windows group)
                    [PrincipalPermission(SecurityAction.Demand,
                    Role=@"DomainName\WindowsGroup")]
                    // Demand that the caller is a specific user
                    [PrincipalPermission(SecurityAction.Demand,
                    Name=@"DomainName\UserName")]
                   

    *

      明确的角色检查。您可以使用 IPrincipal 接口执行角色检查。

      IPrincipal.IsInRole(@"DomainName\WindowsGroup");
         

何时使用

使用不带模拟功能的 Windows 身份验证的情况:

    *

      Web 服务的客户端可以通过使用 Windows 帐户来标识,而 Windows 帐户则可以由服务器验证。
    *

      您需要使用受信任的子系统模型并且在 Web 服务中对客户端进行授权,然后使用固定标识访问下游资源(例如数据库),从而为连接池提供支持。

更多信息

    *

      有关 Windows 身份验证和模拟的详细信息,请参见“ASP.NET 安全性”一章。
    *

      有关 URL 授权的详细信息,请参见“ASP.NET 安全性”一章中的“URL 授权注意事项”。

使用固定标识的 Windows 身份验证

Web.config 中的 <identity> 元素支持可选的用户名和密码属性,可以使用该元素为 Web 服务配置特定的固定标识以进行模拟。这显示在以下配置文件片段中。

<identity impersonate="true"
userName="registry:HKLM\SOFTWARE\YourSecureApp\
identity\ASPNET_SETREG,userName"
password="registry:HKLM\SOFTWARE\YourSecureApp\
identity\ASPNET_SETREG,password" />

本示例显示了 <identity> 元素,其中凭证使用 aspnet_setreg.exe 实用工具在注册表中进行加密。明文形式的 userName 和 password 属性值被指向包含加密凭证的安全注册表项和命名值替代。有关此实用工具的详细信息及下载,请参见 Microsoft 知识库中的文章Q329290“HOW TO:Use the ASP.NET Utility to Encrypt Credentials and Session State Connection Strings”。
何时使用

当在 Windows 2000 服务器上使用 .NET Framework 1.0 时,不推荐使用固定的模拟标识。这是因为您需要授予 ASP.NET 进程帐户“充当操作系统的一部分”权限。 ASP.NET 进程需要此权限,因为它使用您提供的凭证执行 LogonUser 调用。

注.NET Framework 1.1 版会在 Windows 2000 中为此方案进行改进。登录会由 IIS 进程执行,因此 ASP.NET 不需要“充当操作系统的一部分”权限。
更多信息

    *

      有关 Windows 身份验证和模拟的详细信息,请参见“ASP.NET 安全性一章”。
    *

      有关 URL 授权的详细信息,请参见“ASP.NET 安全性”一章中的“URL 授权注意事项”。

返回页首
配置安全性

本节说明配置 ASP.NET Web 服务安全性所需的实际步骤。图 4 总结了这些情况。

f08sn03
图 4. 配置 ASP.NET Web 服务安全性
配置 IIS 设置

有关如何配置 IIS 安全设置的详细信息,请参见“ASP.NET 安全性”一章中的“配置安全性”,因为该信息也适用于 ASP.NET Web 服务。
配置 ASP.NET 设置

应用程序级配置设置保存在 Web.config 文件中,该文件位于 Web 服务的虚拟根目录中。请配置以下设置:

   1.

      配置身份验证。应该在 Web 服务虚拟根目录下的 Web.config 文件中基于每个 Web 服务对它进行设置(而不是在 Machine.config 中)。

      <authentication mode="Windows|None" />
         

      注Web 服务目录不支持 Passport 或表单身份验证。对于自定义和消息级身份验证,请将模式设置为“无”。
   2.

      配置模拟和授权。有关详细信息,请参见“ASP.NET 安全性”一章中的“配置安全性”。

更多信息

有关 URL 授权的详细信息,请参见“ASP.NET 安全性”一章中的“URL 授权注意事项”。
保护资源

应该使用“ASP.NET 安全性”一章中介绍的相同方法来保护 Web 资源的安全。另外,对于 Web 服务,应该考虑从生产服务器上的 Machine.config 中删除 HTTP-GET 和 HTTP-POST 协议。
禁用 HTTP-GET、HTTP-POST

默认情况下,客户端可以使用以下三个协议与 ASP.NET Web 服务进行通信:HTTP-GET、HTTP-POST 和 HTTP 上的 SOAP。应该在生产计算机上禁用计算机级别的 HTTP-GET 和 HTTP-POST 协议支持,因为生产计算机不需要这两个协议。这可避免出现潜在的安全隐患,使有害的 Web 页面无法访问在防火墙后面运行的内部 Web 服务。

注禁用这些协议意味着,新客户端将无法使用 Web 服务测试页中的 Invoke 按钮来测试 XML Web 服务。相反,您必须使用 Microsoft Visual Studio_ .NET 开发系统添加对 Web 服务的引用,以便创建一个测试客户端程序。您可能需要在开发计算机上启用这些协议,使开发人员能够使用测试页进行测试。
在整个计算机中禁用 HTTP-GET 和 HTTP-POST 协议

   1.

      编辑 Machine.config。
   2.

      在 <webServices> 元素中,注释掉 HTTP-GET 和 HTTP-POST 支持的命令行。完成后,Machine.config 应该如下所示。

      <webServices>
          <protocols>
          <add name="HttpSoap"/>
          <!-- <add name="HttpPost"/> -->
          <!-- <add name="HttpGet"/>  -->
          <add name="Documentation"/>
          </protocols>
          </webServices>
         

   3.

      保存 Machine.config。

      注 在特殊情况下,Web 服务客户端使用 HTTP-GET 或 HTTP-POST 与 Web 服务进行通信,您可以在应用程序的 Web.config 文件中添加对这些协议的支持,方法是:创建 <webServices>,然后使用 <protocol> 和 <add> 元素添加对这些协议的支持(如上所示)。

更多信息

有关保护资源安全的详细信息,请参见“ASP.NET 安全性”一章中的“配置安全性”。
安全通信

结合使用 SSL 和 IPSec 来保护通信链路的安全。
更多信息

    *

      有关使用 SSL 调用 Web 服务的更多信息,请参见“How To Call a Web Service Using SSL”。
    *

      有关在两台计算机之间使用 IPSec 的信息,请参见“How To Use IPSec to Provide Secure Communication Between Two Servers”。

返回页首
将身份验证的凭证传递给 Web 服务

在调用 Web 服务时,您可以使用 Web 服务代理来完成该操作;Web 服务代理是一个本地对象,它公开一组与目标 Web 服务相同的方法。

可以使用 Wsdl.exe 命令行实用工具来生成 Web 服务代理。另外,如果您使用 Visual Studio .NET,则还可以通过在项目中添加 Web 引用来生成代理。

注 对于要为其生成代理的 Web 服务,如果将它配置为需要使用客户端证书,则在添加引用时必须暂时禁用该要求,否则就会出现错误。在添加引用后,必须记住将该服务重新配置为需要使用证书。

另一个方法是给用户应用程序提供脱机的 Web 服务描述语言 (WSDL) 文件。如果 Web 服务接口发生变化,则必须记住对它进行更新。
指定用于 Windows 身份验证的客户端凭证

如果您正在使用 Windows 身份验证,则必须使用 Web 服务代理的 Credentials 属性指定用于身份验证的凭证。如果您没有明确地设置该属性,则无需任何凭证即可调用 Web 服务。如果需要 Windows 身份验证,这会导致出现 HTTP 状态 401,拒绝访问响应。
使用 DefaultCredentials

不能隐式地传递客户端凭证。Web 服务使用者必须在代理上设置凭证和身份验证详细信息。要将客户端的 Windows 安全性上下文(通过模拟线程令牌或进程令牌)传递给 Web 服务,您可以将 Web 服务的 Credentials 属性设置为 CredentialCache. DefaultCredentials (如下所示)。

proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;

在使用此方法之前,请注意以下事项:

    *

      仅当使用 NTLM、Kerberos 或协商身份验证时,此方法才传递客户端凭证。
    *

      如果客户端应用程序(例如,Windows 表单应用程序)调用 Web 服务,则可以从用户的交互式登录会话中获取凭证。
    *

      除非配置了模拟功能(此时,服务器端应用程序使用被模拟的调用者的标识),否则,服务器端应用程序(例如,ASP.NET Web 应用程序)使用进程标识。

使用特定凭证

若要在调用 Web 服务时使用一组特定的身份验证凭证,请使用以下代码。

CredentialCache cache = new CredentialCache();
cache.Add( new Uri(proxy.Url), // Web service URL
"Negotiate",        // Kerberos or NTLM
new NetworkCredential("username", "password", "domainname") );
proxy.Credentials = cache;

在上面的示例中,请求的协商身份验证类型导致 Kerberos 或 NTLM 身份验证。
请求特定的身份验证类型

如以下所述,您应该请求特定的身份验证类型。避免直接使用 NetworkCredential 类,如以下代码所示。

proxy.Credentials = new
NetworkCredential("username", "password", "domainname");

在生产代码中应该避免出现这种情况,因为您无法控制 Web 服务使用的身份验证机制,因此也无法控制使用凭证的方式。

例如,可能期望得到来自服务器的 Kerberos 或 NTLM 身份验证质询,但实际却可能收到一个基本质询。在这种情况下,会以明文形式将提供的用户名和密码发送到服务器。
设置 PreAuthenticate 属性

可以将代理的 PreAuthenticate 属性设置为 true 或 false。将其设置为 true 可以提供特定的身份验证凭证,以便通过 Web 请求传递 WWW-authenticate HTTP 标头。这可以避免 Web 服务器拒绝请求的访问,并在后续重试请求中执行身份验证。

注 仅当 Web 服务第一次成功地进行身份验证后,才能使用预身份验证。预身份验证对第一次 Web 请求没有任何影响。

private void ConfigureProxy( WebClientProtocol proxy,
string domain, string username,
string password )
{
// To improve performance, force pre-authentication
proxy.PreAuthenticate = true;
// Set the credentials
CredentialCache cache = new CredentialCache();
cache.Add( new Uri(proxy.Url),
"Negotiate",
new NetworkCredential(username, password, domain) );
proxy.Credentials = cache;
proxy.ConnectionGroupName = username;
}

使用 ConnectionGroupName 属性

注意,上述代码设置 Web 服务代理的 ConnectionGroupName 属性。仅当用于连接 Web 服务的安全性上下文根据不同请求发生变化时,才需要使用该属性(如下所述)。

如果 ASP.NET Web 应用程序连接到 Web 服务并传递原调用者的安全性上下文(通过使用 DefaultCredentials 或者设置显式凭证,如上所示),则应该在 Web 应用程序中设置 Web 服务代理的 ConnectionGroupName 属性。这可防止未验证身份的新客户端重用到 Web 服务(该服务与以前的客户端身份验证凭证关联)的已验证身份的旧 TCP 连接。在使用 HTTP KeepAlives 或出于 IIS 的性能考虑而启用身份验证持续功能时,会出现连接重用。

将 ConnectionGroupName 属性设置为能够区分调用者的标识符(例如调用者的用户名),如上面的代码片段所示。

注如果没有通过 Web 应用程序将原调用者的安全性上下文传递给 Web 服务,而是,Web 应用程序使用固定标识(例如,Web 应用程序的 ASP.NET 进程标识)连接到 Web 服务,则不需要设置 ConnectionGroupName 属性。在此方案中,连接安全性上下文在从一个调用者传递到下一个调用者时,保持不变。
从非 Windows 客户端调用 Web 服务

可以将多种身份验证方法用于跨浏览器的方案中。它们是:

    *

      证书身份验证。使用跨平台的 X.509 证书。
    *

      基本身份验证。有关如何根据自定义数据存储使用基本身份验证(不需要使用 Active Directory)的示例,请参见 http://www.rassoc.com/gregr/weblog/stories/2002/06/26/webServicesSecurityHttpBasicAuthenticationWithoutActiveDirectory.html。
    *

      GXA 消息级方法。使用 Web 服务开发工具包来实现 GXA (WS-Security) 解决方案。
    *

      自定义方法。例如,在 SOAP 标头中传递凭证。

代理服务器身份验证

Visual Studio .NET 的 添加 Web 引用 对话框不支持代理服务器身份验证(但是,下一版本的 Visual Studio .NET 对它提供支持)。因此,在添加 Web 引用时,可能会出现 HTTP 状态 407 响应:“需要代理验证”。

注 通过浏览器查看 .asmx 文件时,可能看不到此错误,因为浏览器自动发送凭证。

要解决这个问题,可以使用 Wsdl.exe 命令行实用工具(而不是 添加 Web 引用 对话框),如下所示。

wsdl.exe /proxy:http:// /pu: /pp: /pd: http://www.YouWebServer.com/YourWebService/YourService.asmx

如果您需要以编程方式设置代理服务器身份验证信息,请使用以下代码。

YourWebServiceProxy.Proxy.Credentials = CredentialsCache.DefaultCredentials;

返回页首
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics