WebAPi之SelfHost自创建证书启动Https疑难解惑及无法正确返回结果

简介:

前言

话说又来需求了,之前对于在SelfHost中需要嵌套页面并操作为非正常需求,这回来正常需求了,客户端现在加了https,老大过来说WebAPi访问不了了,这是什么情况,我去试了试,还真是这个情况,不知道如何下手啊,最终为了解决这个问题,漫长的探索之旅就这样开始了,希望给需要在SelfHost下启动Https的童鞋一点启示和帮助。

话题引入

当在客户端发送请求发送不过去时看了看谷歌控制台显示的消息大意是不能混合使用即客户端为https,则WebAPi不能为http,估计是为了安全的问题,于是乎问题就比较明朗了,只需要将WebAPi修改成https即可,直接将SelfHost中地址修改为Https显然是不行的必须要借助证书并开启对应的端口才行,既然我们已经分析完毕,接下来我们解决WebAPi启动Https的问题即可。开始想到去申请的一个免费的证书就行,但是由于是将WebAPi安装在本地Windows服务中且ip不固定,所以免费的证书则不再可取,只能自行创建证书来解决这个问题。但是我对于证书几乎从未接触过,一无所知,不知从哪里下手,这一漫长的过程就从此开始。

解决SelfHost启动Https

在园中搜索有关自创建证书的答案,基本要么是IIS,要么是WCF创建证书,不过还是有了一点思路,提供了自创建证书需要的命令,开始有一点思绪。当看到如下一条命令时我要惊呆了,难道就这样解决了吗,so  easy!

第一次尝试

http add urlacl url=https://+:port/ user=""

结果发现这只是url的保留项而已。

第二次尝试

我们通过VS开发命令来创建证书 

第一步:

MakeCert -sv d:DevelopmentCA.pvk -n "CN=WebAPi CA" d:DevelopmentCA.cer -b 09/20/2016 -e 12/31/2050 -r

【注意】:该命令最后一个-r不能缺少,-r是创建自创建证书的标识,否则当利用Pvk2pfx创建私钥时则会出现【ERROR: File not found.(Error Code = 0x80070002)】

结果变成如下:

第二步:

打开MMC将创建的证书导入到受信任的颁发证书机构中,则变成如下这样:

第三步:

拿到该证书的指纹并监听ip以及端口,通过如下命令进行:

http add sslcert ipport=0.0.0.0:8084 certhash=‎996645BAB7169F2AFD7599A696DA2586862843C6 appid={41992502-E5D4-4794-BB01-D4A7414480CC}

一切都是如此的完美,最后看下结果,再次让我大失所望:

此时我已经处在崩溃的边缘,搜索这个原因的答案,都无法解决,此时只能求助万能的stackoverflow,看到这个答案令人惊喜一番:

http://stackoverflow.com/questions/13076915/ssl-certificate-add-failed-when-binding-to-port

大意是将自创建的证书要通过MMC首先导入到【个人】证书中才行,于是乎将其拖到个人证书中看看。

结果依然是这个错误,当回过来再看上述所有回答答案时,下面一个回答简直是拯救了我,这个问题困扰我一天,让我无比激动。请看这句话:

You can easily check if your certificate has private a key as so: mmc - certificates - local machinepersonal. Look at the icon of the certificate - it MUST have key sign on the icon.

还要在本地计算中的个人证书中看自创建的证书左上角是否有个小钥匙,这个钥匙也就是私钥,我们还得创建私钥才行,通过如下命令进行。

第四步:

创建证书的私钥

Pvk2pfx -pvk DevelopmentCA.pvk -spc DevelopmentCA.cer -pfx DevelopmentSSL.pfx -po password

接下来我们再来运行第三步则成功如下:

我们接下来运行程序https:localhost:8084来验收成果,结果如下:

那么这个问题又该如何解决呢?可能有些人就得说了,点击下面的高级直接前往不就可以了吗,虽然这样式可以接受,但是在我们项目中,是通过【设备】去访问WebAPi,基于这点绝对不可行,so must kill it。当我各种尝试后发现这样做却可以。我们将 MakeCert -sv d:DevelopmentCA.pvk -n "CN=WebAPi CA" d:DevelopmentCA.cer -b 09/20/2016 -e 12/31/2050 -r 中的CN修改为localhost即颁发给localhost时却可以,重复性的动作则不再演示,给演示最终结果如下:

注意:当到这里时如果你还是发现证书是无效时请进行如下操作,参考资料来源于搜索时来自于youtube的一段视频演示,下面请看:

将演示最后中【允许将标识符用于受保护内容(可能需要重新重启计算机)】去掉即可。

到了这里关于在WebAPi之SelfHost启动Https的问题基本上解决了一大半,对于我来说,对于你来说可能已经Over,但是在实际场景中却还没完成。当在测试时发现如上压根不会请求到WebAPi,此时在谷歌控制台却出现如下的错误:

::Net_Error_Response

第三次尝试

解决客户端无法访问localhost。

百思不得其解,搜索资料时以为是跨域的问题,结果却不是,在客户端那边是用的WebAPi的本地IP来访问,所以想想是不是localhost不行呢。本想偷点懒,在Hosts文件夹里对localhost进行映射,结果依然不行,于是乎访问地址变成:https:192.168.3.6:8084最终完事。

到了这里也就完成了90%,个人还不是很满足,寻思着虽然有一点是绕不过去,那就是首先得将证书导入【受信任的颁发机构中】,但是还需要通过MMC将证书导入个人证书,这一点是我无法接受,我继续开始探索之旅。通过代码的形式将证书导入到MMC的【个人】证书中。 

第四次尝试

通过代码形式将证书导入到【个人】证书中,而非通过MMC导入寻求解决方案。

通过运行如下代码来尝试创建访问https证书:

复制代码
            var fileName = AppDomain.CurrentDomain.BaseDirectory + "DevelopmentSSL.pfx";
            var cert = new X509Certificate2(fileName, "password");
            var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
            store.Open(OpenFlags.ReadWrite);
            store.Add(cert);
            store.Close();


            Process p = new Process();
            p.StartInfo.FileName = "netsh.exe";
            p.StartInfo.Arguments = string.Format("http add sslcert ipport=0.0.0.0:8084 certhash={0} appid={1}", cert.GetCertHashString(), "{" + "41992502-E5D4-4794-BB01-D4A7414480CC"+"}");
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardOutput = true;            
            p.Start();
            p.Close();
复制代码

此时通过如下命令来查看https是否已经开启:

netsh http show sslcert

结果未看到显示开启的端口,此时想或许是否是权限不够呢?于是将启动进程的身份运行以【管理员】身份运行,在上述启动进程中添加如下代码:

 p.StartInfo.Verb = "runas";

此时并未有什么影响,需要开启的端口依然岿然不动,将WebAPi寄宿在Windows服务中,我们是利用批处理来进行,于是尝试利用批处理部署一下来看看,看下演示结果:

 

利用批处理则圆满完成任务并满足要求,不知道为何直接并用管理员身份运行不可,或许是权限还是不够吧,至少还是找到了一种可行的解决方案!

无法正确返回结果

当一切准备就绪时,前端又反应返回的结果不正确不能解析,一波未平一波又起,继续fighting,在控制台如下显示:

这个结果闻所未闻,居然出现一个【 k__BackingField 】 字段,经过查询相关资料得出:在WebAPi中默认是利用JSON.Net中的【 DefaultContractResolver 】来解析对象,当对解析对象上添加【 Serializable 】对象时则会造成上述原因,例如:

    [Serializable]
    public class Person
    {
        public int Age { get; set; }
    }

此时应将【Serializable】特性去除或者在全局配置添加如下语句才能正确显示需要的结果,来忽略默认特性:

            config.Formatters.JsonFormatter.SerializerSettings.ContractResolver =
  new DefaultContractResolver { IgnoreSerializableAttribute = true };

【建议】:无论是有无添加上述序列化特性,建议都在全局配置添加上述忽略默认序列化特性。

参考资料:

http://stackoverflow.com/questions/29701891/k-backingfield-remove-in-c-sharp-seen-via-swashbuckle-swagger

http://stackoverflow.com/questions/35259333/jsonmediatypeformatter-formatting-with-k-backingfield

这一切是不是就这样完了呢?任务算是完成了,为了对证书有更加深入的理解,我们来拓展一下证书知识。

证书知识扩展

两个服务器之间是如何利用证书来进行相互之间的信任呢?请看下图:

在如上图中,管理员通过交换双方之间的公钥中的指纹来建立二者服务器之间的信任关系。对于证书上述我们也已经演示在.NET中通过【 X509Certificate2 】来实现,下面我们来看看这个类。

第一点:证书和PKCS #12/PFX文件的不同 

X509Certificate2此类有两个属性即Public Key(公钥)和Private Key(私钥),当我们导入证书时可以是否导出该私钥,在Windows中典型的证书是以扩展名.cer结尾,当然它没有包含私钥。

下面我们可以这样导出一个证书:

            var fileName = AppDomain.CurrentDomain.BaseDirectory + "DevelopmentCA.cer";
            var cert = new X509Certificate2(fileName);
            File.WriteAllBytes(@"d:Hello.cer", cert.Export(X509ContentType.Cert));

有时我们需要导出私钥,此时私钥及扩展名.Pfx结尾在另外一个文件,可以通过如下导出:

File.WriteAllBytes("Hello.pfx", cert.Export(X509ContentType.Pkcs12, (string)null));

Hello.pfx实际上就是一个PKCS#12文件,它可以作为一个单独文件来储存需要加密对象,做普遍的用途当然也就是用X509Certificate2来存储私钥,有关更多知识请参考:

https://en.wikipedia.org/wiki/PKCS_12

第二点:证书存储

关于这点上述也已经演示,我们通过MMC打开的是控制台证书管理器,可以将当前用户或本地计算机账户导入其中,若只是想看当前用户证书则可以通过certmgr.msc来打开。那么通过代码形式如何进行呢?如下:

var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite);
store.Add(certificate);
store.Close();

可以将证书导入到通过StoreLocation.CurrentUser映射到当前用户,通过StoreName.My映射到当前用户个人证书中,也可以是本机计算机账户中的其他机构中通过上述枚举即可。此时则会添加如下注册表中

HKEY_CURRENT_USER\SOFTWARE\Microsoft\SystemCertificates

或者通过桌面路径

C:\Users\username\AppData\Roaming\Microsoft\SystemCertificates\My\Certificates

当然在本地计算中则是如下路径:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates

第三点:理解私钥

我们上述已经叙述过证书中是不带私钥,私钥时单独作为一个文件来使用,那么私钥到底存储在什么地方呢?我们给出如下代码:

复制代码
            var fileName = AppDomain.CurrentDomain.BaseDirectory + "DevelopmentSSL.pfx";
            var cert = new X509Certificate2(fileName,"password", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
            var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
            store.Open(OpenFlags.ReadWrite);
            store.Add(cert);
            store.Close();
复制代码

此时私钥会存储在如下注册表中:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates\MY\Keys

如果我们进行如下修改将MachineKeySet修改为UserKeySet:

复制代码
            var fileName = AppDomain.CurrentDomain.BaseDirectory + "DevelopmentSSL.pfx";
            var cert = new X509Certificate2(fileName,"password", X509KeyStorageFlags.UserKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
            var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
            store.Open(OpenFlags.ReadWrite);
            store.Add(cert);
            store.Close();
复制代码

此时则会存储在如下地方:

C:\Users\username\AppData\Roaming\Microsoft\SystemCertificates\My\Keys\

此时可能会出现一点问题,当将证书导入并供本地计算机去使用,但是此时私钥却个人用户文件夹中,要是计算机中的其他账户想要访问这个私钥可能没有这个权限或者说得不到这个私钥。

关于枚举X509KeyStorageFlags的几点说明:

(1)Exportable :创建证书时指定它可以用于备份私钥。

(2)PersistKeySet:创建证书时指定它可以导入一次并使用多次。

(3)UserKeySet:创建证书时指定它可以在另外一个账户使用它。

(4)MachineKeySet:创建证书时指定它可能导致其他账户没有权限或者访问不到私钥导致该私钥不存在。

第四点:创建证书时谨慎

谨慎导出证书利用字节数组 var certificate = new X509Certificate2(bytes); 此时会将文件写到临时文件夹中,此时有可能临时文件夹中有关此文件不会得到有效的清理,导致临时文件夹膨胀。

工具介绍

如下网址这里可以看到通过MakeCert程序来创建证书已经被弃用(在PowerShell4.0之前我们可以下载MakeCert来自创建证书)。

https://msdn.microsoft.com/library/windows/desktop/aa386968.aspx

现在创建的证书可以通过PowerShell来进行(不过系统在Windows 8 或者Windows Server 2012或者Windows 8.1或者Windows Server 2012 R2),有关此命令的介绍详情请见如下网址:

https://technet.microsoft.com/library/hh848633

看起来好像很难,实则比MakeCert命令更加简洁明了,我们来看看(需要切换到PowerShell)。

(1)利用如下命令来创建证书并获取到其指纹

 New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname localhost

颁发给localhost,并将其保存到本地计算机中的【个人】证书下,结果得到如下:

(2)需要导出证书时,需要用一个变量来保存密码

$pwd = ConvertTo-SecureString -String "Pa$$w0rd" -Force -AsPlainText

(3)导出pfx,指定第一步获取到的指纹和第二步保存的密码

Export-PfxCertificate -cert cert:\localMachine\my\CE0976529B02DE058C9CB2C0E64AD79DAFB18CF4 -FilePath d:cert.pfx -Password $pwd

总结 

本节到这里算是完全结束了,将在WebAPi使用过程中遇到的问题到一并叙述了一遍,其中整个做完花费了三天时间,写这篇博客花费了一天,很久没有坐着花费接近一天的精力来写一篇博客,不过确确实实涨了不少知识,文中有关内容若有不妥之处,欢迎批评,同时也为了后续让其他需要用到的童鞋少走点坑也是值得的,当然这里在WebAPi中我们也需要认证客户端是否已经采用ssl加密证书,通过继承DelegatingHandler来进行处理,例如如下:

            var uri = new UriBuilder(request.RequestUri);
            uri.Scheme = Uri.UriSchemeHttps;
            uri.Port = _httpsPort;
            //TO DO

在这里非常感谢园友【幻天芒】,遇到难题解决不了或是没什么思路都在向他请教,感谢他的不厌其烦和指导,再次表示感谢。在这里也提前预祝各位园友国庆快乐。






本文转自Jeffcky博客园博客,原文链接:http://www.cnblogs.com/CreateMyself/p/5904002.html,如需转载请自行联系原作者

目录
相关文章
|
2月前
|
安全 算法 网络协议
解析:HTTPS通过SSL/TLS证书加密的原理与逻辑
HTTPS通过SSL/TLS证书加密,结合对称与非对称加密及数字证书验证实现安全通信。首先,服务器发送含公钥的数字证书,客户端验证其合法性后生成随机数并用公钥加密发送给服务器,双方据此生成相同的对称密钥。后续通信使用对称加密确保高效性和安全性。同时,数字证书验证服务器身份,防止中间人攻击;哈希算法和数字签名确保数据完整性,防止篡改。整个流程保障了身份认证、数据加密和完整性保护。
|
11天前
|
安全 算法 数据建模
HTTPS证书类型和品牌一览
HTTPS证书(SSL证书)是保障网站数据传输安全与身份可信认证的重要工具,适用于电商、企业官网等各类平台。证书主要分为DV(域名验证)、OV(企业验证)、EV(扩展验证)三种安全级别,以及单域名、通配符、多域名等不同覆盖类型。品牌方面,既有高性价比的国产锐安信、CFCA,也有国际知名的Sectigo、Digicert。
|
3月前
|
监控 运维
HTTPS 证书自动化运维:https证书管理系统- 自动化监控
本文介绍如何设置和查看域名或证书监控。步骤1:根据证书状态选择新增域名或证书监控,线上部署推荐域名监控,未部署选择证书监控。步骤2:查询监控记录详情。步骤3:在详情页查看每日定时检测结果或手动测试。
HTTPS 证书自动化运维:https证书管理系统- 自动化监控
|
3月前
|
Linux 持续交付 调度
HTTPS 证书自动化运维:https证书管理系统-自动化部署
本指南介绍如何部署Linux服务器节点。首先复制生成的Linux脚本命令,然后将其粘贴到目标服务器上运行。接着刷新页面查看节点记录,并点击“配置证书”选择证书以自动部署。最后,节点部署完成,后续将自动调度,无需人工干预。
HTTPS 证书自动化运维:https证书管理系统-自动化部署
|
3月前
|
运维
HTTPS 证书自动化运维:https证书管理系统之自动化签发
通过访问【https://www.lingyanspace.com】注册账户,进入证书服务菜单并新增证书。填写域名(单域名、多域名或泛域名),创建订单后添加云解析DNS记录进行质检。确认完成后可下载证书,并支持后续查看、更新和定时更新功能。证书过期前15天自动更新,需配置邮箱接收通知。
HTTPS 证书自动化运维:https证书管理系统之自动化签发
|
3月前
|
机器学习/深度学习 人工智能 运维
HTTPS 证书自动化运维:展望未来发展趋势
HTTPS证书自动化运维正朝着更智能、高效和安全的方向发展。未来系统将提升自动化程度,减少人工干预,实现自动签发、续订与部署;深度集成多云平台,提供无缝管理体验;增强高级安全功能如加密算法和威胁检测;优化用户界面,降低使用门槛;支持更多操作系统,确保跨平台一致性;引入AI/ML技术,预测需求并自动解决问题;加强标准化与互操作性,促进生态系统协作。同时,系统将持续扩展功能、优化性能、支持国际化,并注重用户反馈,为全球用户提供优质的证书管理服务。
|
3月前
|
运维 监控 数据安全/隐私保护
HTTPS 证书自动化运维:HTTPS 证书管理系统之使用指南
本文详细介绍【灵燕空间HTTPS证书管理系统】(https://www.lingyanspace.com)的配置与使用,涵盖注册账户、邮箱配置及证书自动签发、监控和部署的一体化指南。通过页面顶部菜单的【视频教程】和【图文教程】,帮助用户从注册到实际应用全面掌握系统操作。最新迭代后,泛域名证书已包含根域名,无需额外申请多域名证书。
|
7月前
|
监控 安全 搜索推荐
设置 HTTPS 协议以确保数据传输的安全性
设置 HTTPS 协议以确保数据传输的安全性
|
4月前
|
网络协议 安全 网络安全
探索网络模型与协议:从OSI到HTTPs的原理解析
OSI七层网络模型和TCP/IP四层模型是理解和设计计算机网络的框架。OSI模型包括物理层、数据链路层、网络层、传输层、会话层、表示层和应用层,而TCP/IP模型则简化为链路层、网络层、传输层和 HTTPS协议基于HTTP并通过TLS/SSL加密数据,确保安全传输。其连接过程涉及TCP三次握手、SSL证书验证、对称密钥交换等步骤,以保障通信的安全性和完整性。数字信封技术使用非对称加密和数字证书确保数据的机密性和身份认证。 浏览器通过Https访问网站的过程包括输入网址、DNS解析、建立TCP连接、发送HTTPS请求、接收响应、验证证书和解析网页内容等步骤,确保用户与服务器之间的安全通信。
297 3
|
5月前
|
安全 搜索推荐 网络安全
HTTPS协议是**一种通过计算机网络进行安全通信的传输协议
HTTPS协议是**一种通过计算机网络进行安全通信的传输协议
119 11