76

关于使 .NET HTTPListener 支持 HTTPS,似乎有很多令人困惑的信息,有时甚至是相互矛盾的信息。我的理解如下:

  • 一个人的 C# 代码需要一个https前缀(例如,https://*:8443),以便侦听器了解它需要在此端口上服务 SSL 请求。

  • 实际的 SSL 握手发生在幕后,并由http.sys(埋在 Windows 机器上的某个地方)处理。C# 代码不必显式管理 SSL 握手,因为它发生在幕后。

  • 需要在机器上拥有“X.509 受信任证书” httpListener,并且该证书需要以某种方式绑定到端口 8443(在此示例中)。

我上面的理解正确吗?如果没有,请教育我。

关于 X.509 证书,我的理解是:

  • 用于makecert创建 X.509 证书。此证书存储在个人存储中,需要转移到受信任的存储(这是 HTTP 侦听器将查看的位置)。看来我可以certMgr用来执行移动,或者我可以mmc用来实现移动。似乎有不止一种 X.509 证书格式(DER, Base64, pks, pswd protected, pksprivate 等)...有我应该使用的首选格式吗?

将证书放入可信存储后,我需要将其绑定到 TCP 端口。我在 Windows 7 上:我应该使用httpcfg还是netsh

4

5 回答 5

89

我做了一堆功课并得到了这个工作。为 .NET HttpListener 添加 SSL 支持的步骤如下:

  1. 更新 C# 应用程序代码以包含https前缀。例子:

    String[] prefixes = { "http://*:8089/","https://*:8443/" };
    

    从代码方面来说就是这样。

  2. 对于证书方面,使用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}
      

      certash 是您的 SSL 证书的指纹。您可以使用 mmc 找到它。appid 在 Visual Studio 中找到...通常在 assembly.cs 中,查找 GUID 值。

可能还有其他方法可以完成上述操作,但这对我有用。

于 2012-07-12T17:55:07.233 回答
42

以下是我在 Windows 上设置独立服务器的详细步骤,使用 OpenSSL 为 C#HTTPListener应用程序创建自签名证书。它包含大量链接,以防您想做进一步的研究。

  1. 通过以下方式在 .NET 中创建独立服务器HttpListener

    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();
    
  2. 创建自签名证书:*

    1. openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365,它将提示您在命令行上输入每个证书字段的值。对于公用名,输入域名(例如localhost
    2. openssl pkcs12 -inkey bob_key.pem -in bob_cert.cert -export -out bob_pfx.pfx, 以便可以在目标机器上使用其密钥导入它。

    *有关使用 的替代方法makecert,请参阅 Walter 自己的答案

  3. 打开本地计算机的证书管理器。当您运行时,它会为当前用户certmgr.msc打开证书管理器,这不是我们想要的。反而:

    1. 从目标计算机上的管理命令提示符处,运行mmc
    2. 按或单击Ctrl + MFile > Add/Remove Snap-in
    3. 选择Certificates,然后单击Add >
    4. 在出现的对话框中,选择Computer Account,然后单击Next
    5. 选择Local Computer。点击Finish,然后Okay
  4. 将证书 ( pfx) 导入目标计算机上的Windows 证书存储区

    1. mmc之前打开的窗口中,向下钻取到Certificates (Local Computer) > Personal
    2. 右键单击Personal,然后单击All Tasks -> Import...
    3. 在出现的对话框的第二个屏幕中,找到并导入您的证书。您必须将文件类型过滤器更改为Personal Information ExchangeAll Files才能找到它
    4. 在下一个屏幕上,输入您在步骤 2.1 中选择的密码,并密切注意第一个复选框。这决定了您的证书存储的安全程度,以及使用的方便程度
    5. 在最后一个屏幕上,选择Place all certificates in the following store。验证它是否显示Personal,然后单击Finish
    6. Trusted Root Certification Authorities对证书部分重复上述导入过程。
  5. 为您的应用程序创建端口关联。在 Windows Vista 及更高版本上netsh,像我一样使用 。(对于 Windows XP 及更早版本,请使用httpcfg

    • 在管理命令行中,键入以下内容以设置SSL 绑定*到您的应用程序和相应的端口。 注意:这个命令很容易出错,因为(在 PowerShell 中)大括号需要转义。以下 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接口)

      * Microsoft 已将SSL 绑定链接从这里重定向到那里

  6. 启动您的网络服务器,一切顺利!

于 2015-11-24T22:23:34.380 回答
6

我们可以使用 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 或更高版本。

于 2019-04-14T17:48:16.123 回答
3

以下命令为 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 或更高版本。需要管理员权限。

于 2020-11-17T12:34:01.197 回答
1

由于在答案中制作您自己的自签名证书对我不起作用,并且问题特别要求使 .NET HTTPListener 能够支持 HTTPS 并要求提供任何提示/建议,因此我想分享我的方法。

您需要一个主机名,例如 www.made-up.com,它需要指向您的 WAN IP 地址(例如,向您的主机提供商索取说明)并将其端口(例如 443)转发到您的本地计算机。不要忘记在本地计算机的防火墙中打开入站 443 端口。

我使用了 https://letsencrypt.org/。在 Windows 上,这不像在 Linux 上那么容易,因为没有任何官方的 certbot ACME 客户端用于 Windows。但是,您可以使用https://github.com/Lone-Coder/letsencrypt-win-simple,其中也有二进制文件。但是“当前仅支持 IIS”。但是您可以轻松地欺骗它在您的计算机上创建一个证书,以便您可以通过 SSL 方式访问您的 HTTP 侦听器:

  1. 安装 IIS(通过打开/关闭的 Windows 功能),在 IIS 中创建一个网站并分配主机名。还要为它建立一个安全的(443 端口)网站。
  2. 运行letsencrypt-win-simple EXE 文件(我使用的是1.9.1 版)。回答问题,让它生成证书。
  3. 之后,您可以停止 de IIS 服务器。

我相信您必须注意生成的刷新任务,因为我不确定几个月后它会成功(您可能必须再次启动 IIS 才能更新证书)。

于 2016-12-27T20:39:06.763 回答