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,出错时真的是误导啊!痛心不已!
要不然出错时老出这个恶心的误导:
更详细的见 http://www.codeproject.com/Tips/197531/Do-not-use-using-for-WCF-Clients
实施步骤:
1.定义接口,要设置ProtectionLevel.Sign,表示只需签名,无需加密
2. 定义实施类
3. 制作client 和server 端的X.509 certificate
这个看看网上怎么用MakeCert.exe
4. 服务器端web。Config
5.客户端的app.Config配置
6. 客户端测试程序
先加载Service Reference,然后
我运行过得到了正确的结果。
还有一些缺点,例如identity没有配置好,不知道在生产环境是不是简单一点,因为有域名。还需要两个X.509 certificates,这个还需要简化
Raw Soap Request
Raw Soap Response
如果你想做一个高效的安全的Web Service, 那么没有必要用WCF framework,手工打造一个,WCF framework为懒人初学者提供很大的方便。手工打造就得对很多细节一清二楚,如果谁想弄一个高效的,能应付大并发流量的,安全的Web Service请联系我。QQ:314544874
有两点折磨了我好长时间,因为断断续续的使用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
相关文章推荐
- 如何在调用WCF服务之前弹出一个确认对话框?
- 如何开发一个高质量的J2EE系统,网络转载
- WCF开发框架形成之旅--如何实现X509证书加密
- 【MSH】如何开发第一个最简单的WCF模块服务(附实例源码)
- 《Nodejs开发加密货币》之八:一个精巧的p2p网络实现
- 如何建立一个WCF服务并将其发布到IIS上
- 如何在调用WCF服务之前弹出一个确认对话框?
- WCF开发框架形成之旅--如何实现X509证书加密
- 如何做一个快速运转的大规模网络开发公司
- 不能启动 Easy Config时如何创建一个新的网络服务
- 一个WCF服务开发与调用的完整示例
- WCF开发框架形成之旅--如何实现X509证书加密
- 一个Windows服务如何host多个wcf服务?
- 一个WCF服务开发与调用的完整示例
- 一个WCF服务开发与调用的完整示例
- WCF技术剖析之二十七: 如何将一个服务发布成WSDL[编程篇]
- WCF技术剖析之二十七: 如何将一个服务发布成WSDL[基于HTTP-GET的实现](提供模拟程序)
- WCF学习笔记 -- 如何用C#开发一个WebService
- wcf入门教程之在.net471中创建一个使用tcp网络协议的wcf控制台开发测试环境
- WCF技术剖析之二十七: 如何将一个服务发布成WSDL[基于WS-MEX的实现](提供模拟程序)