首先說明,僅僅使用證書只解決了數據明文安全問題的,但請求是否合法,還要通過其它手段,如:雙向證書驗證 或者 證書+用戶驗證的方案
VS控制台下創建證書示意:
1,默認創建證書 makecert -n "CN=www.ecepdi.com" Wcf_EdocFileService.cer (-n搬發給)
2, 創建自簽名搬發者證書 makecert -n "CN=www.ecepdi.com" -r Wcf_EdocFileService.cer (-r代表自簽署)
3,創建帶私鑰部分.pvk的證書 makecert -n "CN=www.ecepdi.com" -r -sv Wcf_EdocFileService.pvk Wcf_EdocFileService.cer
4,創建指定位置證書 makecert -r -pe -n "CN=www.ecepdi.com" -sr LocalMachine -ss My -sky exchange (-sr 位置 -n 存儲位置)
參數明細參與
MSDN http://msdn.microsoft.com/zh-cn/bfsktky3(vs.80).aspx
如果是IIS做宿主的話最好采好第4種方式,將證書生成到LocalMachine 下My目錄, 因為放到CurrentUser/My 下即使設置了密鑰的Newwork Service/IIS_USER權限也沒法正常讀取密鑰 ,
所以建議生成到LocalMachine/My下 makecert -r -pe -n "CN=www.ecepdi.com" -sr LocalMachine -ss My -sky exchange
完成證書制作后,可以通過mmc添加單元->證書->添加本地計算機 找到個人下剛生成的證書。
你可以將證書復制到其它受信區(個人/受信人/受信任的搬發機構等),只要設置好對應的WCF節點指向這些區,當然設置None就會檢索所有區域
<authentication certificateValidationMode="None"/> 可以訪問所有受信區,如果需要設置固定位置,則證書位置與WCF此節點設置要一致
設置IIS宿主對密鑰訪問權限
此時WCF IIS宿主仍無法讀取到讀取密鑰 可以借助下面兩種方式實現
1,下載FindPrivateKey.exe工具,通過命令查找指定證書
FindPrivateKey My LocalMachine -n "CN=www.ecepdi.com" 或
FindPrivateKey My LocalMachine -t "指紋密鑰"
查找到對應的密鑰存放位置,然后找到此文件,在文件屬性安全添加Network Service/IIS_USERS 用戶的讀權限
2.下載winhttpcertcfg.exe工具(還要設置IIS_USERS的權限)
WinHttpCertCfg.exe -g -c LOCAL_MACHINE\MY -s "證書名" -a Network Service
設置完成后,IIS宿主不是馬上就可以訪問密鑰,所以不要急,可以iisreset命令重啟IIS
此時在IIS宿主就可以正常訪問WCF服務了 ,平時在VS調試時,大家用的都是VS的服務器,所以不會碰到此類問題,但部署到IIS就發現不能正常訪問了。
建議WEB開發時,把項目屬性->WEB->使用本地IIS WEB服務器,以免碰到VS里調試正常但到IIS就不正常了,就不知道怎么回事了。
使用證書應避免客戶端與服務端時間差超過5分鍾,當兩端時間相差過長,則會證書安全錯誤.(可能原因加密過期)
WCF IIS 站點x.509證書Web.config配置
服務端:

<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding">
<security>
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="DemoService.FileService" behaviorConfiguration="DemoService.FileServiceBehavior">
<endpoint address="" binding="wsHttpBinding" contract="DemoService.IFileService" bindingConfiguration="wsHttpEndpointBinding">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="DemoService.FileServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="None"/>
</clientCertificate>
<serviceCertificate findValue="WcfServer"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
客戶端:

<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IFileService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="1073741824"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="1073741824"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Certificate" negotiateServiceCredential="true"
algorithmSuite="Default" establishSecurityContext="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8066/DemoService/FileService.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IFileService"
contract="Edoc.IFileService" name="WSHttpBinding_IFileService"
behaviorConfiguration="WSHttpBinding_IFileService" >
<identity>
<dns value="WcfServer" />
</identity>
</endpoint>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="WSHttpBinding_IFileService">
<clientCredentials>
<clientCertificate findValue="WcfServer" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My"/>
<serviceCertificate>
<authentication certificateValidationMode="None"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
在測試過程中,客戶端配置 <identity> <dns value="WcfServer" /></identity> 會被要求設置指向服務端的證書名,所以DNS這個位置不是IP地址而服務端的證書名。
WCF IIS站點 雙向證書 配置
服務端:

<system.serviceModel>
<services>
<service behaviorConfiguration="DocumentFileService.FileServiceBehavior"
name="DocumentFileService.FileService">
<endpoint address="" binding="wsHttpBinding" contract="DocumentFileService.IFileService" bindingConfiguration="DocumentFileService.IFileService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="DocumentFileService.FileServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceThrottling maxConcurrentCalls="1000" maxConcurrentSessions="1000" maxConcurrentInstances ="1000"/> <!-- 並發控制,最大連接數-->
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="Custom" customCertificateValidatorType="DocumentFileService.ServiceX509CertificateValidator,DocumentFileService"/>
</clientCertificate>
<serviceCertificate findValue="EdocFileServer" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="DocumentFileService.IFileService">
<security mode="Message">
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
客戶端:

<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IFileService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="1073741824" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="1073741824" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None" realm=""/>
<message clientCredentialType="Certificate" negotiateServiceCredential="true" algorithmSuite="Default" establishSecurityContext="true"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://ecepdi-da2:8066/FileService.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IFileService" contract="EdocFileService.IFileService" name="WSHttpBinding_IFileService" behaviorConfiguration="WSHttpBinding_IFileService">
<identity>
<dns value="EdocFileServer"/>
</identity>
</endpoint>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="WSHttpBinding_IFileService">
<clientCredentials>
<clientCertificate findValue="EdocFileClient" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My"/>
<serviceCertificate><!--關閉客戶端驗證服務端證書過程-->
<authentication certificateValidationMode="Custom" customCertificateValidatorType="ECEPDI.Document.WCF_X509.ClientX509CertificateValidator,ECEPDI.Document"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>