如何配置WCF服务端使用HTTPS通信

其实本文的原题目是《如何搭建“假冒的”WCF HTTPS服务器》,但是写完一想,那其实只是我遇到的特殊场景,而真正有意义的用途就是现在的题目了。依旧是一波非常奇葩的操作,估计WCF都很少有人在用了,但至少也算是干货吧。

场景是这样的:某软件通过WCF(如果你不懂什么是WCF,也可以往下看,本文并非探讨WCF技术细节)与认证服务器进行验证,以核实你的License。两者之间是以HTTPS的形式连接。虽然我可以通过各种方式撸软件本身解决这个问题,但是软件经常更新,最方便的方式当然是撸一个假冒的服务器与软件交流,对于任何请求都回复“对 没错 很OK 我批准了 这是合法的”。——这也是目前很多人都在用的JBLS[1]和KMS的原理。

当然本软件并没有JBLS/KMS那么复杂,它向一个固定(写死在程序中)的URL(https://auth.xxx.com)请求WCF服务,这个URL还是HTTPS的。首先,由于刚才说到我们的限制条件是不改程序,因此我们要重定向URL地址,让软件去找我们的假冒服务器——这大家都能想到,可以通过改hosts解决。在hosts文件中加入一行:

127.0.0.1 auth.xxx.com

这是本机实验时的写法,在试验成功后,则可以把IP地址改到部署的服务器上。

随后就可以开始写服务器了。WCF服务的编程超过了本文的范围,不过还是提一点。比如本软件请求WCF服务,那么就一定会有一个客户端和服务端通用的接口(IService),客户端调用这个接口的方法,会发送到服务器执行对应方法的实现,随后结果再返回到客户端。那么我们要复原这个服务,首先要取得这个接口。一种方式是反编译导出软件代码,挑出其中相关的接口类。另一种方法则是直接访问那个服务URL,看看对面服务器有没有*.svc?wsdl这种元数据发现服务(不过一般Release部署是没有的……),若有则可通过“svcutil auth.xxx.com/service.svc?wsdl”这样的命令直接生成代码。

 

随后来探讨如何为你的WCF自托管服务器启用SSL。这是本文主要探讨的主题,其实这个主题并不是只用在搞破坏上,你自己搓的WCF甚至其他自托管服务要实现这一点也需要这些步骤。这里只探讨自托管,除此之外你还可以托管在IIS上。若是IIS托管,下面的netsh步骤可以在IIS管理器中操作,可能会更容易一些。不过对于很多小霸王来说,IIS托管消耗的资源远大于自托管,所以我一般建议诸位小霸王用户不使用IIS,而是选择自托管(包括.NET Core自托管)。

首先需要创建一个证书。很久以前我也是makecert的用户,直到我发现了xca。

有了这个工具,你可以把其他做证书的玩意全丢掉了。首先创建一个RSA私钥,随后进入“证书”选项卡,新建一个CA证书。需要注意的地方有:

  • “签名算法”建议选择SHA-256,否则Chrome会认为不够安全而产生怀疑(但这不影响程序使用)
  • “模板”选择CA,然后Apply all
  • subject中的内容至少要填写commonName(CN)
  • “私钥”一栏选择刚刚创建的私钥
  • 有效期选长一点,默认是1年,不便于使用

创建好证书后,导出为p12格式,随后双击文件导入到系统,要注意选择导入位置到“受信任的根证书颁发机构”。这样我们就有了一个系统信任的根证书。今后对于其他想要使用这个服务器的用户,也需要导入这个证书。但是我们不能把私钥也提供给用户,所以再导出一份crt格式的提供给用户(也是需要安装到“受信任的根证书颁发机构”)。

有了可信的根证书,我们还需要针对URL再造一个SSL用的证书。这时我们需要再新建一个RSA私钥。这次新建证书的注意点如下:

  • “签名”一栏选择用刚才的CA证书签名
  • “签名算法”建议选择SHA-256,否则Chrome会认为不够安全而产生怀疑(但这不影响程序使用)
  • “模板”选择HTTPS Server,然后Apply all
  • subject中的commonName(CN)必须填写为对应域名,如*.xxx.com或者auth.xxx.com,建议前者
  • “私钥”一栏选择刚刚创建的私钥(无法使用CA证书的私钥)
  • 如果你刚才CN填的是*.xxx.com,那么进到Extension选项卡添加X509v3 Subject Alternative Name,Type选择DNS,创建(至少)两个,内容分别为auth.xxx.com和xxx.com。这个步骤同样是为取得Chrome等现代浏览器信任,因为Chrome已经不接受没有Subject Alternative Name的证书了。

创建好后,导出p12,双击导入。这个证书是只用于服务器的,因此可以导入到“个人”路径下,而且不提供给用户。

 

现在我们有了证书,但这还不够,下一步我们需要把SSL证书配置到443(HTTPS)端口。这个步骤可以参考:

https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-a-port-with-an-ssl-certificate

首先右键SSL证书文件——打开,进入mmc控制台的证书功能界面(或者运行mmc,添加功能,证书),找到SSL证书,双击查看详细信息,找到指纹(Thumbprint)一栏,把指纹复制下来,并去掉空格。

然后以管理员权限运行命令:

netsh http add sslcert ipport=0.0.0.0:443 certhash={thumbprint} appid={guid}

其中thumbprint就是刚才去掉空格的指纹,guid随便写一个GUID(如{00112233-4455-6677-8899-AABBCCDDEEFF}),这是方便确认APP用的。

如果以后同一个端口要换一个证书,则要执行:

Netsh http delete sslcert ipport=0.0.0.0:443

以删除证书。

 

随后在你服务器中添加一些代码导入证书(“*.xxx.com”是证书的CommonName):

ServiceHost host = ...;
host.Credentials.ServiceCertificate.SetCertificate(
                    StoreLocation.LocalMachine,
                    StoreName.My,
                    X509FindType.FindBySubjectName, "*.xxx.com");

host.Credentials.ClientCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck;

确保你的ServiceHost的URL路径与软件内写的URL路径除了域名之外的部分是完全一样的,随后运行,打开软件测试,就可以发现软件连到了我们的服务器上,成功。

总结:搭建服务器,维护者需要进行的操作包括:

  1. 导入CA证书和SSL证书(需要管理员权限)
  2. 用命令将SSL证书绑定到443端口(需要管理员权限)
  3. 运行服务器程序(可能需要管理员权限)

之后,用户需要进行的操作包括:

  1. 导入一个CA证书(这可以通过程序实现,不过程序需要具有管理员权限才能导入到那个路径。导入操作只需要执行一次,而且以后不用了也不需要删除)[2]
  2. 改host添加一行重定向(也可以通过程序甚至批处理实现。不过程序也需要具有管理员权限。以后不用了需要删除,以让用户切换回真服务器)

除了简单的操作之外,更大的意义在于这个方案不会受到软件重装或者版本升级的影响。而且通过服务器我们能够对用户的使用情况有一个大致的了解。

 

注1:关于JBLS:JB的软件与服务器建立连接时有RSA公钥证书的验证,不修改软件的话,就要保证服务端有对应的(本来应该只掌握于JB自己手中的)证书,目前我还不是特别清楚JBLS是怎么做到的,但按照常理来想的话应该是那位作者小哥成功完成了大质数分解的壮举(这并不是没有可能的,如果他能掌握校级及以上的高性能的计算资源的话)。而我所制作的RegiSharpter相较于JBLS,优点在于不需要联网或是搭建本地服务器浪费资源,离线即可激活,缺点则在于没有那么通用。

注2:其实更合理的操作是服务方到网上申请一个证书,比如从阿里云就可以申请免费证书。但正规申请的证书只能绑定到自己购置的域名上(这是理所当然的)。这样申请来的合法证书就不需要用户手动去导入和信任了。

 

参考文献

https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-a-port-with-an-ssl-certificate

https://stackoverflow.com/questions/3292330/certificate-on-a-wcf-service-that-does-not-use-iis/5278348#5278348

https://stackoverflow.com/questions/13385817/wcf-https-ssl-self-hosted-cert-how-to-get-working-correctly

https://stackoverflow.com/questions/3140526/wcf-https-vs-http

https://stackoverflow.com/questions/27294589/creating-self-signed-certificate-for-domain-and-subdomains-neterr-cert-commo

 

添加评论

Loading