WebSocket安全连接自签名证书 [英] WebSocket secure connection self signed certificate

查看:1394
本文介绍了WebSocket安全连接自签名证书的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目标是一个Web应用程序,该Web应用程序与用户PC上安装的C#应用​​程序交换信息. 客户端应用程序是websocket服务器,浏览器是websocket客户端.

The goal is a web application that exchanges information with an C# application that is installed on the user's pc. The client application is the websocket server and the browser is the websocket client.

最后,用户浏览器中的websocket客户端是通过Angular持久创建的,并且该应用程序在PC上运行并正在执行某些操作.

In the end the websocket client in the user's browser is created persistently via Angular and the application is running on the pc and doing some things.

使用的C#库为 WebSocket-Sharp . websocket客户端是普通的javascript.

The C# library used is WebSocket-Sharp. The websocket client is normal javascript.

显然,此连接仅发生在本地,因此客户端连接到localhost. 由于网站是通过HTTPS保护的,因此websocket也必须得到保护.为此,C#应用程序在启动时会创建一个证书(实际上只是出于测试目的).

Obviously this connection happens only local so the client connects to localhost. As the website is secured via HTTPS the websocket has to be secured too. For this purpose the C# application creates a certificate when it starts up (it's just for testing purposes actually).

由于证书不受信任,因此连接无效.客户端的所有服务器检查均已禁用,但无法建立连接.

The connection doesn't works because the certificate is untrusted. All server checks for the client are disabled but the connection won't establish.

这是创建服务器的部分

_server = new WebSocketServer($"wss://localhost:4649")
{
    SslConfiguration =
    {
        ServerCertificate = Utils.Certificate.CreateSelfSignedCert(),
        ClientCertificateRequired = false,
        CheckCertificateRevocation = false,
        ClientCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true
    }
};
_server.AddWebSocketService<CommandsBehaviour>("/commands");
_server.AddWebSocketService<NotificationsBehaviour>("/notifications");

_server.Start();

这是使用BouncyCastle创建证书的方式

This is how the certificate is created with BouncyCastle

private static AsymmetricKeyParameter CreatePrivateKey(string subjectName = "CN=root")
{
    const int keyStrength = 2048;

    // Generating Random Numbers
    var randomGenerator = new CryptoApiRandomGenerator();
    var random = new SecureRandom(randomGenerator);

    // The Certificate Generator
    var certificateGenerator = new X509V3CertificateGenerator();

    // Serial Number
    var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), random);
    certificateGenerator.SetSerialNumber(serialNumber);

    // Issuer and Subject Name
    var subjectDn = new X509Name(subjectName);
    var issuerDn = subjectDn;
    certificateGenerator.SetIssuerDN(issuerDn);
    certificateGenerator.SetSubjectDN(subjectDn);

    // Valid For
    var notBefore = DateTime.UtcNow.Date;
    var notAfter = notBefore.AddYears(70);

    certificateGenerator.SetNotBefore(notBefore);
    certificateGenerator.SetNotAfter(notAfter);

    // Subject Public Key
    var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
    var keyPairGenerator = new RsaKeyPairGenerator();
    keyPairGenerator.Init(keyGenerationParameters);
    var subjectKeyPair = keyPairGenerator.GenerateKeyPair();

    return subjectKeyPair.Private;
}

public static X509Certificate2 CreateSelfSignedCert(string subjectName = "CN=localhost", string issuerName = "CN=root")
{
    const int keyStrength = 2048;
    var issuerPrivKey = CreatePrivateKey();

    // Generating Random Numbers
    var randomGenerator = new CryptoApiRandomGenerator();
    var random = new SecureRandom(randomGenerator);
    ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA512WITHRSA", issuerPrivKey, random);
    // The Certificate Generator
    var certificateGenerator = new X509V3CertificateGenerator();
    certificateGenerator.AddExtension(X509Extensions.SubjectAlternativeName, false, new GeneralNames(new GeneralName[] { new GeneralName(GeneralName.DnsName, "localhost"), new GeneralName(GeneralName.DnsName, "127.0.0.1") }));
    certificateGenerator.AddExtension(X509Extensions.ExtendedKeyUsage, true, new ExtendedKeyUsage((new ArrayList() { new DerObjectIdentifier("1.3.6.1.5.5.7.3.1") })));

    // Serial Number
    var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
    certificateGenerator.SetSerialNumber(serialNumber);

    // Signature Algorithm
    //const string signatureAlgorithm = "SHA512WITHRSA";
    //certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm);

    // Issuer and Subject Name
    var subjectDn = new X509Name(subjectName);
    var issuerDn = new X509Name(issuerName);
    certificateGenerator.SetIssuerDN(issuerDn);
    certificateGenerator.SetSubjectDN(subjectDn);

    // Valid For
    var notBefore = DateTime.UtcNow.Date;
    var notAfter = notBefore.AddYears(70);

    certificateGenerator.SetNotBefore(notBefore);
    certificateGenerator.SetNotAfter(notAfter);

    // Subject Public Key
    var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
    var keyPairGenerator = new RsaKeyPairGenerator();
    keyPairGenerator.Init(keyGenerationParameters);
    var subjectKeyPair = keyPairGenerator.GenerateKeyPair();

    certificateGenerator.SetPublicKey(subjectKeyPair.Public);

    // self sign certificate
    var certificate = certificateGenerator.Generate(signatureFactory);

    // corresponding private key
    var info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);


    // merge into X509Certificate2
    var x509 = new X509Certificate2(certificate.GetEncoded());

    var seq = (Asn1Sequence)Asn1Object.FromByteArray(info.ParsePrivateKey().GetDerEncoded());
    if (seq.Count != 9)
    {
        throw new PemException("malformed sequence in RSA private key");
    }

    var rsa = RsaPrivateKeyStructure.GetInstance(seq); //new RsaPrivateKeyStructure(seq);
    var rsaparams = new RsaPrivateCrtKeyParameters(
        rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2, rsa.Coefficient);

    x509.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
    return x509;

}

此行为是合乎逻辑的,尽管很奇怪,因为不应在本地执行证书检查. 有可能绕过这个问题吗?我已经考虑过将发行者证书安装到受信任的证书,但这不是最佳解决方案.

This behaviour is logical although it is strange as the cert check shouldn't be performed locally. Is there a possibility to bypass this problem? I already thought about installing the issuer certificate to the trusted certs but this is not an optimal solution.

推荐答案

您是否尝试过对此总而言之,您可以尝试以下几种选择:

To summarize, it looks like there are a few options you could try:

  • 使用指定的--ignore-certificate-errors参数启动Chrome.

  • Start Chrome with the --ignore-certificate-errors argument specified.

在使用相同自签名证书的同一端口上启动HTTP服务器,浏览至该服务器并接受该证书,之后您应该能够使用WebSocket连接.

Start an HTTP server on the same port that takes the same self-signed certificate, browse to it, and accept the certificate, after which you should be able to use the WebSocket connection.

将Firefox network.websocket.allowInsecureFromHTTPS上的配置选项设置为true,然后使用ws://而不是wss://地址.

Set the configuration option on Firefox network.websocket.allowInsecureFromHTTPS to true, then use the ws:// rather than the wss:// address.

如果所有这些都是为了测试,并且您有可能控制这种事情,那么我认为其中一个或多个应该可以工作.如果您需要标准的最终用户能够执行此操作,那么我认为您将需要其他解决方案.正如您所发现的,您是否将服务器设置为不关心证书并不重要,客户端必须最终决定是要接受证书还是不接受连接.

If all this is is for testing and you have the possibility to control that sort of thing, then I think one or more of those should work. If you need your standard end user to be able to do this, I think you'll a need a different solution. As you've found, it doesn't matter if you set the server up to not care about the certificate, the client has to ultimately decide if it wants to accept the certificate or it won't accept the connection.

这篇关于WebSocket安全连接自签名证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆