B2B中的WCF,如何用WCF开发一个只需签名不加密的网络服务(Secured Web Service)

2 篇文章 0 订阅
1 篇文章 0 订阅

有些关键的企业间应用通常涉及到金钱需要足够的安全才敢通讯,所以就有了安全的网络服务(Secured Web Service)。微软以前用WSE来实施,我觉得还不是很难。后来WSE被微软放弃了,要大家都转到WCF,不过WCF 包装过度,选项太多,一旦涉及安全,非常得难,反复了好几次才搞出只需签名不加密的网络服务,这是因为WCF错误信息不够详细甚至误导。微软经常夹带私货,无视真正的企业需求,例如和java实施的安全网络服务互通,通常java实施的安全网络服务互通只需HTTPS和X.509签名。X.509签名用来确定用户身份,HTTPS用来加密通讯,这通常已经足够安全了。但是微软就是不告诉你如何实现这个,整天扯他妈的wsHttpBinding,网上都是一般东抄西抄的关于wsHttpBinding教学材料或者混蛋,非常难以找到用WCF去实现只需签名的网络服务的材料,气得你半死。我觉得wsHttpBinding用途不是很大,是微软的私货。

有两点折磨了我好长时间,因为断断续续的使用WCF,半桶水晃荡。

1)PeerTrust:The certificate is valid if it is in the trusted people store. 我把它记成Personal Store即 My,老遇到 至少有一个Certificate无效的问题,困恼了很长时间。

2)千万不要用“using” 配合WCF Channel/Client/ChannelFactory,出错时真的是误导啊!痛心不已!

要不然出错时老出这个恶心的误导:

failed: System.ServiceModel.CommunicationObjectFaultedException : 
The communication object, System.ServiceModel.Channels.ServiceChannel, 
cannot be used for communication because it is in the Faulted state.
    
    Server stack trace: 
    at System.ServiceModel.Channels.CommunicationObject.Close(TimeSpan timeout)
    
    Exception rethrown at [0]: 
    at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
    at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
    at System.ServiceModel.ICommunicationObject.Close(TimeSpan timeout)
    at System.ServiceModel.ClientBase`1.System.ServiceModel.ICommunicationObject.Close(TimeSpan timeout)
    at System.ServiceModel.ClientBase`1.Close()
    at System.ServiceModel.ClientBase`1.System.IDisposable.Dispose()
其实根本没有连接上服务器,但是不知为什么有 Server stack trace。

更详细的见 http://www.codeproject.com/Tips/197531/Do-not-use-using-for-WCF-Clients


实施步骤:

1.定义接口,要设置ProtectionLevel.Sign,表示只需签名,无需加密

[ServiceContract(ProtectionLevel =ProtectionLevel.Sign) ]
public interface IService
{
    [OperationContract]
    string GetData(int value);
}

2. 定义实施类

public class Service : IService
{
	public string GetData(int value)
	{
		return string.Format("You entered: {0}", value);
	}	
}

3. 制作client 和server 端的X.509 certificate

这个看看网上怎么用MakeCert.exe

4. 服务器端web。Config

  <system.serviceModel>
    <services>
      <service name="Service" behaviorConfiguration="certificateBehavior">
        <!-- Service Endpoints -->
        <endpoint address="" binding="basicHttpBinding"  bindingConfiguration="bindingCertificate" 
                  contract="IService" >
          <!-- 
              Upon deployment, the following identity element should be removed or replaced to reflect the 
              identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
              automatically.
          -->
          <identity>
            <dns value="192.168.5.95"/>
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <bindings>
      <basicHttpBinding>
        <binding name="bindingCertificate">
          <security mode="Message">
            <message clientCredentialType="Certificate"/>
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="certificateBehavior">
          <serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
          <serviceAuthorization principalPermissionMode="None"/>
          <serviceCredentials>
            <clientCertificate>
              <authentication revocationMode="NoCheck"  certificateValidationMode ="None"/>
            </clientCertificate>
            <serviceCertificate findValue="WCFService"
                                x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My"/>
          </serviceCredentials>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

5.客户端的app.Config配置

 <system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="NewBehavior0">
          <clientCredentials>
            <clientCertificate findValue="WCFClient" x509FindType="FindBySubjectName" />
            <serviceCertificate>
              <authentication revocationMode="NoCheck" />
            </serviceCertificate>
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <bindings>
      <customBinding>
        <binding name="BasicHttpBinding_IService" sendTimeout="00:05:00">
          <security defaultAlgorithmSuite="Default" authenticationMode="MutualCertificate"
            requireDerivedKeys="false" securityHeaderLayout="Lax" includeTimestamp="true"
            messageProtectionOrder="SignBeforeEncrypt" messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
            requireSignatureConfirmation="false">
            <localClientSettings detectReplays="true" />
            <localServiceSettings detectReplays="true" />
          </security>
          <textMessageEncoding messageVersion="Soap11" />
          <httpTransport />
        </binding>
      </customBinding>
    </bindings>
    <client>
      <endpoint address="http://192.168.5.95/jqtest/service.svc" binding="customBinding"
        bindingConfiguration="BasicHttpBinding_IService" contract="ServiceReference1.IService"
        name="BasicHttpBinding_IService" behaviorConfiguration="NewBehavior0">
        <identity >
          <certificateReference findValue="WCFService" storeLocation ="CurrentUser" storeName ="My" x509FindType ="FindBySubjectName"/>
          <!--<dns value="192.168.5.95"/> -->
        </identity>
      </endpoint>
    </client>
  </system.serviceModel>

6. 客户端测试程序

先加载Service Reference,然后

            try {
                ServiceClient client = new ServiceClient();
                client.GetData(1);
                client.Close();
            }
            catch (Exception ex) {
                Console.Error.WriteLine(ex);
            }

我运行过得到了正确的结果。

还有一些缺点,例如identity没有配置好,不知道在生产环境是不是简单一点,因为有域名。还需要两个X.509 certificates,这个还需要简化

Raw Soap Request

POST http://192.168.5.95/jqtest/service.svc HTTP/1.1
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://tempuri.org/IService/GetData"
Host: 192.168.5.95
Content-Length: 2689
Expect: 100-continue
Connection: Keep-Alive

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <s:Header>
        <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <u:Timestamp u:Id="uuid-24e0db20-53b0-4d34-818e-fdcc62eb8029-1">
                <u:Created>2013-09-23T21:55:07.637Z</u:Created>
                <u:Expires>2013-09-23T22:00:07.637Z</u:Expires>
            </u:Timestamp>
            <o:BinarySecurityToken u:Id="uuid-d8e1d8a0-b63f-422a-8310-5ebae6932f73-2" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">MIIBsTCCAV+gAwIBAgIQ7TyxyvewZ7NN/WaG0DiFwDAJBgUrDgMCHQUAMBYxFDASBgNVBAMTC1Jvb3QgQWdlbmN5MB4XDTEzMDkxODE2MTY0MloXDTM5MTIzMTIzNTk1OVowFDESMBAGA1UEAxMJV0NGQ2xpZW50MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7lJcoEpV6s+BYVdYfc/21yFBut8nTUx5EtHXEAomx4upgeuZse72c3yIQVu/mPg+GvbVfhHsalO99j0ttoNco53U7EFEapdt434Pqrwkeiy28lmA+0AYtVAknM0YSByNfZ/3ElnGjqy06Sds5znpEc4dTPTrskaAwMyglLGBsxwIDAQABo0swSTBHBgNVHQEEQDA+gBAS5AktBh0dTwCNYSHcFmRjoRgwFjEUMBIGA1UEAxMLUm9vdCBBZ2VuY3mCEAY3bACqAGSKEc+41KpcNfQwCQYFKw4DAh0FAANBAGNGPOUdO3gAJ2cISN4BJC9Wpm5UfqsaTPznxXC45AHksA8UCzMryqq4V0cB7rhjvccA9oDMLZkxfYSBkBdYgH4=</o:BinarySecurityToken>
            <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
                <SignedInfo>
                    <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
                    <Reference URI="#_1">
                        <Transforms>
                            <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                        </Transforms>
                        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                        <DigestValue>65ERoR9h4UgYatBlGT88N0dSTqk=</DigestValue>
                    </Reference>
                    <Reference URI="#uuid-24e0db20-53b0-4d34-818e-fdcc62eb8029-1">
                        <Transforms>
                            <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                        </Transforms>
                        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                        <DigestValue>YBX4WAjPRQ3/w+oikyGOyLRiQSc=</DigestValue>
                    </Reference>
                </SignedInfo>
                <SignatureValue>ERppkcG2gGl6wGCVbI4vSPV0V/B2zwOWH77giUcsefFFzAzVHkoefv1TdjIDrPnJcVrfeUlJqn60IS3N1a/yg1MX+YRiRPtvpI+YDQzRCqXzhgZh0fA16wzVy1tVi+OLdrLpQxwBGt+tMY3Wv65skSiHzWqLfUQqfTmmqdwOr7M=</SignatureValue>
                <KeyInfo>
                    <o:SecurityTokenReference>
                        <o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-d8e1d8a0-b63f-422a-8310-5ebae6932f73-2"/>
                    </o:SecurityTokenReference>
                </KeyInfo>
            </Signature>
        </o:Security>
    </s:Header>
    <s:Body u:Id="_1">
        <GetData xmlns="http://tempuri.org/">
            <value>1</value>
        </GetData>
    </s:Body>
</s:Envelope>



Raw Soap Response

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Server: Microsoft-IIS/7.0
X-Powered-By: ASP.NET
Date: Mon, 23 Sep 2013 21:54:54 GMT
Content-Length: 1862

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <s:Header>
        <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <u:Timestamp u:Id="uuid-bd361f67-714a-4deb-8f9c-8a7d8954a8ef-1">
                <u:Created>2013-09-23T21:54:54.197Z</u:Created>
                <u:Expires>2013-09-23T21:59:54.197Z</u:Expires>
            </u:Timestamp>
            <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
                <SignedInfo>
                    <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
                    <Reference URI="#_1">
                        <Transforms>
                            <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                        </Transforms>
                        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                        <DigestValue>EVvi+44ZpmFe3H+0tz7MfNmrHyI=</DigestValue>
                    </Reference>
                    <Reference URI="#uuid-bd361f67-714a-4deb-8f9c-8a7d8954a8ef-1">
                        <Transforms>
                            <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                        </Transforms>
                        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                        <DigestValue>M6CgzU5+kM8WBslUdy2Xr9v4TJY=</DigestValue>
                    </Reference>
                </SignedInfo>
                <SignatureValue>VCb5v4zi3+YA2PCyfUWkSUKQXEInYkqBJivmzRK5jWGEpsJ3ZJfqkzAfk3//eWjT38vrHGGgUJwQRkPWLW69M7ue3S4Tn8UpNcyI2IzbklIoJBjCVtdwP7BqRsDwHRGsynJXHhNSHSllzLrTnWNs9fPH1aSvqOKhuNHgfMlNBcU=</SignatureValue>
                <KeyInfo>
                    <o:SecurityTokenReference>
                        <X509Data>
                            <X509IssuerSerial>
                                <X509IssuerName>CN=Root Agency</X509IssuerName>
                                <X509SerialNumber>-32031604220717131174929833209954748223</X509SerialNumber>
                            </X509IssuerSerial>
                        </X509Data>
                    </o:SecurityTokenReference>
                </KeyInfo>
            </Signature>
        </o:Security>
    </s:Header>
    <s:Body u:Id="_1">
        <GetDataResponse xmlns="http://tempuri.org/">
            <GetDataResult>You entered: 1</GetDataResult>
        </GetDataResponse>
    </s:Body>
</s:Envelope>

虽然我花了一堆时间来讲解WCF,但是做过复杂的安全网络服务后,认为WCF就是垃圾,谁用谁倒霉!我天天在公司里教唆别的程序员说 I hate WCF!

简单的网络服务用asmx,复杂的用HttpWebRequest,XML Serializer/Deserializer,Soap UI。
本文乃硬座宝发明人原创,如需转载请一定注明原文作者 硬座宝发明人 也。
如果你想做一个高效的安全的Web Service, 那么没有必要用WCF framework,手工打造一个,WCF framework为懒人初学者提供很大的方便。手工打造就得对很多细节一清二楚,如果谁想弄一个高效的,能应付大并发流量的,安全的Web Service请联系我。QQ:314544874


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值