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,如需转载请自行联系原作者

目录
相关文章
|
10天前
|
安全 算法 网络协议
ip地址https证书免费试用—政企单位专用
IP地址HTTPS证书为基于公网IP的服务提供加密保护,JoySSL等机构提供免费试用,帮助政企用户降低安全成本。用户需注册账号、申请证书、提交CSR并验证IP所有权,最后安装证书并测试。免费证书有效期短,但能有效保障数据安全,提升用户信任度及合规性。
|
7天前
|
安全 网络安全 数据安全/隐私保护
内网/局域网IP地址申请https证书方法
为内网/局域网IP地址申请HTTPS证书,可增强数据传输的安全性。首先确定固定的内网IP地址,选择可信的证书颁发机构,注册并申请免费或付费SSL证书,提交相关信息,支付费用(如有)。证书申请成功后,下载并配置于服务器,确保通过浏览器访问时显示为安全连接。注意定期更新证书,确保持续的安全保障。此过程适用于局域网内部通信加密,提升内网服务的安全水平。
|
15天前
|
安全 数据安全/隐私保护
IP地址https证书免费申请教程
本教程详细介绍如何免费申请IP地址HTTPS证书,涵盖准备、申请、审核、下载与部署阶段。从确认IP地址、选择CA、注册账户到验证控制权,最后完成证书部署,确保数据传输安全。注意证书有效期较短,需及时续签。
|
21天前
|
安全 物联网 数据建模
IP地址能否申请HTTPS证书?
IP地址可申请HTTPS证书,但需满足特定条件。首先,该IP须为公网IP,具备唯一性和可控性。证书类型限于DV或OV级别,不支持EV。申请过程包括所有权验证及端口开放。适用于服务器间通信及IoT设备等场景。申请时需注意成本、浏览器兼容性和安全性问题。
|
26天前
|
安全 应用服务中间件 网络安全
免费ip地址https证书申请方法
IP SSL证书用于保障IP地址与浏览器间的数据传输安全,多数需付费购买。JoySSL现提供免费试用版,申请流程包括:访问官网、注册账号(需输入特定注册码230922)、选择证书类型、填写申请信息、验证IP控制权、等待审核、下载及部署证书。确保IP地址独立可控,信息准确,及时续期。
|
1月前
|
安全 网络安全 数据安全/隐私保护
政务单位IP地址https证书
政务单位IP地址HTTPS证书是一种专为只有IP地址而无域名的政务网站设计的数字证书,用于加密通信、确保数据安全并提升用户信任度。申请流程包括选择证书颁发机构、提交申请并验证、部署证书等步骤。证书有效期通常为一年或多年,需定期更新以确保安全性。
|
1月前
|
算法 安全 网络安全
等保、密评使用的IP地址https证书
等保和密评是确保网络安全的重要环节。IP地址的HTTPS证书通过加密数据传输、符合等保密评要求、提升IP身份辨识度,起到关键作用。证书需国产化、支持国密算法,并建议采用OV或EV证书。申请流程包括准备、选择服务商、申请与验证、签发与部署、验证与测试。定期检查证书有效期,确保持续有效性。
|
域名解析 缓存 网络协议
Let's Encrypt 配置 HTTPS 免费泛域名证书
Let's Encrypt 配置 HTTPS 免费泛域名证书
2023 0
|
安全 算法 小程序
互联网并发与安全系列教程(17) - 生产环境配置HTTPS证书
互联网并发与安全系列教程(17) - 生产环境配置HTTPS证书
146 0
|
3月前
|
Linux Docker Windows
Docker配置https证书案例
本文介绍了如何为Docker的Harbor服务配置HTTPS证书,包括安装Docker和Harbor、修改配置文件以使用证书、生成自签名证书、配置证书以及验证配置的步骤。
203 2
Docker配置https证书案例