支持 HTTPS 的 Httplistener
Posted
技术标签:
【中文标题】支持 HTTPS 的 Httplistener【英文标题】:Httplistener with HTTPS support 【发布时间】:2012-07-09 08:10:06 【问题描述】:关于使 .NET HTTPListener 支持 HTTPS 的信息似乎很多令人困惑,有时甚至相互冲突。我的理解如下:
一个人的 C# 代码需要一个 https
前缀(例如,https://*:8443
),以便侦听器了解它需要在此端口处理 SSL 请求。
实际的 SSL 握手发生在幕后,由 http.sys
处理(埋在 Windows 机器的某个地方)。 C# 代码不必显式管理 SSL 握手,因为它发生在幕后。
需要在httpListener
机器上拥有“X.509 可信证书”,并且该证书需要以某种方式绑定到端口 8443(在本例中)。
我上面的理解正确吗?如果没有,请教育我。
关于 X.509 证书,我的理解是:
使用makecert
创建 X.509 证书。此证书存储在个人存储中,需要转移到受信任的存储(这是 HTTP 侦听器将查看的位置)。看来我可以使用certMgr
来执行移动,或者我可以使用mmc
来实现移动。似乎有不止一种 X.509 证书格式(DER
、Base64
、pks
、pswd 保护、pks
私有等)...有我应该使用的首选格式吗?李>
将证书放入受信任的存储区后,我需要将其绑定到 TCP 端口。我在 Windows 7 上:我应该使用 httpcfg
还是 netsh
?
【问题讨论】:
【参考方案1】:以下命令为 localhost 生成 10 年的自签名证书,将其导入本地计算机存储并在输出中显示 Thumbprint (certhash):
powershell -Command "New-SelfSignedCertificate -DnsName localhost -CertStoreLocation cert:\LocalMachine\My -NotAfter (Get-Date).AddYears(10)"
然后您可以从输出中复制指纹并使用 netsh.exe 将证书附加到 localhost:443,例如:
netsh http add sslcert ipport=localhost:443 certhash=110000000000003ed9cd0c315bbb6dc1c08da5e6 appid=00112233-4455-6677-8899-AABBCCDDEEFF
适用于 Windows 8 或更高版本。需要管理员权限。
【讨论】:
这听起来非常高效和简单。问题 - 什么是 appid? - 我从哪里得到它? @GoguCelMare 这个答案可以帮助你***.com/questions/537173/…【参考方案2】:我做了很多功课并得到了这个工作。为 .NET HttpListener 添加 SSL 支持的步骤如下:
更新 C# 应用程序代码以包含 https
前缀。示例:
String[] prefixes = "http://*:8089/","https://*:8443/" ;
从代码方面来说就是这样。
对于证书方面,使用Windows SDK 命令控制台或 Visual Studio Professional 命令控制台
使用makecert.exe
创建证书颁发机构。示例:
makecert -n "CN=vMargeCA" -r -sv vMargeCA.pvk vMargeCA.cer
使用makecert.exe
创建 SSL 证书
makecert -sk vMargeSignedByCA -iv vMargeCA.pvk -n "CN=vMargeSignedByCA" -ic vMargeCA.cer vMargeSignedByCA.cer -sr localmachine -ss My
使用 MMC GUI 在 Trusted Authority 存储中安装 CA
使用 MMC GUI 在个人存储中安装 SSL 证书将证书绑定到IP address:port
和应用程序。示例:
netsh http add sslcert ipport=0.0.0.0:8443 certhash=585947f104b5bce53239f02d1c6fed06832f47dc appid=df8c8073-5a4b-4810-b469-5975a9c95230
certhash 是您的 SSL 证书的指纹。您可以使用 mmc 找到它。 appid 在 Visual Studio 中找到...通常在 assembly.cs 中,查找 GUID 值。
可能还有其他方法可以完成上述操作,但这对我有用。
【讨论】:
嗯,我尝试按照这些提示做所有事情,但我无法完成最后一步 - 它说某些参数无效...... 我注意到,当我复制并粘贴到命令行时,有时会出现“?”出现在“certhash=”和实际密钥之间。仔细检查您的输入。 有什么方法可以将根 CA 证书链接到中间证书? @WalterKelt 您的回答对我帮助很大,并且几乎填补了现有文档中的所有空白。但是,有一些我必须自己填写,因此我发布了我的分步过程作为答案。干杯! @WalterKelt 只是一个猜测,但可能是可执行项目的属性文件夹中的 AssemblyInfo 文件中的 Guid【参考方案3】:由于在答案中制作您自己的自签名证书对我不起作用,并且该问题特别要求使 .NET HTTPListener 能够支持 HTTPS 并要求提供任何提示/建议,因此我想分享我的方法。
您需要一个主机名,例如 www.made-up.com,它需要指向您的 WAN IP 地址(例如,向您的主机提供商咨询)并转发其端口,例如443,到您的本地机器。不要忘记在本地计算机的防火墙中打开入站 443 端口。
我使用了https://letsencrypt.org/。在 Windows 上,这不像在 Linux 上那么容易,因为没有任何用于 Windows 的官方 certbot ACME 客户端。但是,您可以使用https://github.com/Lone-Coder/letsencrypt-win-simple,其中也有二进制文件。但是“当前仅支持 IIS”。但是您可以很容易地欺骗它在您的计算机上创建一个证书,以便您可以通过 SSL 方式访问您的 HTTP 侦听器:
-
安装 IIS(通过打开/关闭的 Windows 功能),在 IIS 中创建一个网站并分配主机名。还要为它建立一个安全的(443 端口)网站。
运行letsencrypt-win-simple EXE文件(我用的是1.9.1版)。回答问题,让它生成证书。
之后,您可以停止 de IIS 服务器。
我相信您必须注意生成的刷新任务,因为我不确定几个月后它会成功(您可能必须再次启动 IIS 才能更新证书)。
【讨论】:
certbot 可与 cygwin 和 IIS 一起使用,如果您能够添加“。” ->“文本/html”mime 类型。执行“pip3 install certbot”,然后将 Web 根目录挂载到标准 posix 路径,然后运行“certbot certonly”。不是最流畅的,但它确实有效。【参考方案4】:以下是我在 Windows 上设置独立服务器的详细步骤,使用 OpenSSL 为 C# HTTPListener
应用程序创建自签名证书。它包含大量链接,以供您进一步研究。
通过HttpListener
在.NET中创建一个独立的服务器:
var prefixes = "http://localhost:8080/app/root", "https://localhost:8443/app/root";
var listener = new HttpListener();
foreach (string s in prefixes)
listener.Prefixes.Add(s);
listener.Start();
创建自签名证书:*
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365
,它将提示您在命令行上输入每个证书字段的值。对于通用名称,请输入域名(例如 localhost
)
openssl pkcs12 -inkey bob_key.pem -in bob_cert.cert -export -out bob_pfx.pfx
,以便可以在目标机器上使用其密钥导入。
*有关使用 makecert
的替代方法,请参阅 Walter 自己的 answer。
为本地计算机打开证书管理器。当您运行certmgr.msc
时,它会为当前用户 打开证书管理器,这不是我们想要的。而是:
-
从目标计算机上的管理命令提示符运行
mmc
按 Ctrl + M,或单击 文件 > 添加/删除快照-in
选择Certificates
,然后点击添加>
在出现的对话框中,选择Computer Account
,然后单击下一步
选择Local Computer
。点击完成,然后点击Okay
将证书(pfx
)导入目标机器上的Windows Certificate Store
-
在之前打开的
mmc
窗口中,向下钻取到 证书(本地计算机) > 个人
右键单击Personal
,然后单击所有任务 -> 导入...
在出现的对话框的第二个屏幕中,找到并导入您的证书。您必须将文件类型过滤器更改为 Personal Information Exchange
或 All Files
才能找到它
在下一个屏幕上,输入您在步骤 2.1 中选择的密码,并密切注意第一个复选框。这决定了您的证书存储的安全程度以及使用的方便程度
在最后一个屏幕上,选择Place all certificates in the following store
。验证它是否显示 Personal
,然后单击 Finish
对Trusted Root Certification Authorities
证书部分重复上述导入过程。
为您的应用程序创建端口关联。在 Windows Vista 及更高版本上,像我一样使用netsh
。 (对于 Windows XP 及更早版本,请使用 httpcfg
)
在管理命令行中,键入以下内容以将 SSL binding* 设置到您的应用程序和相应的端口。 注意:这个命令是easy to get wrong,因为(在PowerShell中)大括号必须是escaped。以下 PowerShell 命令将起作用:
netsh http add sslcert ipport=0.0.0.0:8443 `
certhash=110000000000003ed9cd0c315bbb6dc1c08da5e6 `
appid=`00112233-4455-6677-8899-AABBCCDDEEFF`
对于cmd.exe
,应使用以下代码:
netsh http add sslcert ipport=0.0.0.0:8443 certhash=110000000000003ed9cd0c315bbb6dc1c08da5e6 appid=00112233-4455-6677-8899-AABBCCDDEEFF
ipport
参数将导致 SSL 证书绑定到每个网络接口上的端口 8443
;要绑定到特定接口(仅),请选择与该网络接口关联的 IP 地址。
certhash
只是证书指纹,去掉了空格
appid
是存储在应用程序的程序集信息中的 GUID。 (旁注:netsh
机制显然是一个 COM 接口,从这个 question 及其答案来看)
* Microsoft 已将 SSL 绑定 链接从 here 重定向到 there。
启动您的网络服务器,一切顺利!
【讨论】:
@Jez IIRC,我只使用Trusted Root Certificate Authorities
证书存储没有问题。您的设置是否有什么特别之处需要证书也位于 Personal
存储中?
当我在安装了证书的机器上运行netsh
命令时,出现错误“SSL 证书添加失败,错误 1312 - 指定的登录会话不存在。它可能已经被终止了。”查看这个问题的答案,看起来证书应该在个人商店中通过netsh
安装它(它谈到运行certutil
和my
而不是root
):***.com/a/19766650/178757
在我的 Windows 上,生成 .pfx 文件的命令使用 Git-(Bash)-for-Windows 挂起。作为解决方案,只需根据openssl-hangs-during-pkcs12-export在命令前添加winpty
即可。
感谢您的宝贵时间,但我自己忘记了我什么时候发表评论的,但我赞成您的回答,所以我想您的回答对我有用,谢谢:)
只是为寻找项目 GUID 的未来读者提供的注释,在 Visual Studio 中,某些项目不再具有程序集信息文件。如果是这种情况,您的项目的 GUID 应该在您的解决方案文件中。只需在记事本中打开您的 .sln 文件并查找类似 XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX 的内容【参考方案5】:
我们可以使用 PowerShell 和 C# 导入证书(无需手动步骤)。
详情见:https://blog.davidchristiansen.com/2016/09/howto-create-self-signed-certificates-with-powershell/
我正在使用此代码:
/// <summary>
/// Create and install a self-signed certificate for HTTPS use
/// </summary>
private static void CreateInstallCert(int expDate, string password, string issuedBy)
// Create/install certificate
using (var powerShell = System.Management.Automation.PowerShell.Create())
var notAfter = DateTime.Now.AddYears(expDate).ToLongDateString();
var assemPath = Assembly.GetCallingAssembly().Location;
var fileInfo = new FileInfo(assemPath);
var saveDir = Path.Combine(fileInfo.Directory.FullName, "CertDir");
if (!Directory.Exists(saveDir))
Directory.CreateDirectory(saveDir);
// This adds certificate to Personal and Intermediate Certification Authority
var rootAuthorityName = "My-RootAuthority";
var rootFriendlyName = "My Root Authority";
var rootAuthorityScript =
$"$rootAuthority = New-SelfSignedCertificate" +
$" -DnsName 'rootAuthorityName'" +
$" -NotAfter 'notAfter'" +
$" -CertStoreLocation cert:\\LocalMachine\\My" +
$" -FriendlyName 'rootFriendlyName'" +
$" -KeyUsage DigitalSignature,CertSign";
powerShell.AddScript(rootAuthorityScript);
// Export CRT file
var rootAuthorityCrtPath = Path.Combine(saveDir, "MyRootAuthority.crt");
var exportAuthorityCrtScript =
$"$rootAuthorityPath = 'cert:\\localMachine\\my\\' + $rootAuthority.thumbprint;" +
$"Export-Certificate" +
$" -Cert $rootAuthorityPath" +
$" -FilePath rootAuthorityCrtPath";
powerShell.AddScript(exportAuthorityCrtScript);
// Export PFX file
var rootAuthorityPfxPath = Path.Combine(saveDir, "MyRootAuthority.pfx");
var exportAuthorityPfxScript =
$"$pwd = ConvertTo-SecureString -String 'password' -Force -AsPlainText;" +
$"Export-PfxCertificate" +
$" -Cert $rootAuthorityPath" +
$" -FilePath 'rootAuthorityPfxPath'" +
$" -Password $pwd";
powerShell.AddScript(exportAuthorityPfxScript);
// Create the self-signed certificate, signed using the above certificate
var gatewayAuthorityName = "My-Service";
var gatewayFriendlyName = "My Service";
var gatewayAuthorityScript =
$"$rootcert = ( Get-ChildItem -Path $rootAuthorityPath );" +
$"$gatewayCert = New-SelfSignedCertificate" +
$" -DnsName 'gatewayAuthorityName'" +
$" -NotAfter 'notAfter'" +
$" -certstorelocation cert:\\localmachine\\my" +
$" -Signer $rootcert" +
$" -FriendlyName 'gatewayFriendlyName'" +
$" -KeyUsage KeyEncipherment,DigitalSignature";
powerShell.AddScript(gatewayAuthorityScript);
// Export new certificate public key as a CRT file
var myGatewayCrtPath = Path.Combine(saveDir, "MyGatewayAuthority.crt");
var exportCrtScript =
$"$gatewayCertPath = 'cert:\\localMachine\\my\\' + $gatewayCert.thumbprint;" +
$"Export-Certificate" +
$" -Cert $gatewayCertPath" +
$" -FilePath myGatewayCrtPath";
powerShell.AddScript(exportCrtScript);
// Export the new certificate as a PFX file
var myGatewayPfxPath = Path.Combine(saveDir, "MyGatewayAuthority.pfx");
var exportPfxScript =
$"Export-PfxCertificate" +
$" -Cert $gatewayCertPath" +
$" -FilePath myGatewayPfxPath" +
$" -Password $pwd"; // Use the previous password
powerShell.AddScript(exportPfxScript);
powerShell.Invoke();
需要 PowerShell 4 或更高版本。
【讨论】:
我的 VS 中缺少 Path.Combine 和 System.Management以上是关于支持 HTTPS 的 Httplistener的主要内容,如果未能解决你的问题,请参考以下文章