您的位置:首页 > 理论基础 > 计算机网络

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

2013-09-24 05:59 495 查看
有些关键的企业间应用通常涉及到金钱需要足够的安全才敢通讯,所以就有了安全的网络服务(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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: