【问题标题】:SslStream and AuthenticationSslStream 和身份验证
【发布时间】:2017-01-25 22:58:40
【问题描述】:

我看了很长时间的 MSDN info 文章,还是没看懂。

基于不需要客户端身份验证的假设:

1.当我调用SslStream.AuthenticateAsServer(...)时,我是在服务器端调用这个方法还是在客户端调用这个方法?

2.在建立SslStream的时候,建立SslStream是只有服务端的责任还是服务端和客户端都负责?

3.如果只是服务端的责任,是不是说客户端不用自己创建SslStream就可以正常使用send()receive()操作?

4.客户端是否需要获取证书文件才能对服务器进行身份验证?

非常感谢您,我真的找不到关于这个主题的太多信息,我已经搜索了很长时间......

【问题讨论】:

    标签: c# ssl certificate ssl-certificate sslstream


    【解决方案1】:

    编辑:MSDN 在此页面底部有一个完整的工作示例:https://msdn.microsoft.com/en-us/library/system.net.security.sslstream?f=255&MSPPError=-2147217396 - 所以您应该真正开始在那里进行试验,因为该示例包含所有内容。

    原答案

    我必须先回答“不需要客户端身份验证”是大多数 SSL 实现的情况。客户端身份验证很少见:您可能会在 VPN 应用、银行业和其他安全应用中看到它。因此,当您尝试使用 SslStream() 时,最好在没有客户端身份验证的情况下启动。

    当您浏览 HTTPS 网站时,您不会使用客户端证书对浏览器进行身份验证,而只是想确认您要连接的服务器名称与证书中找到的 CNAME 匹配,并且服务器证书由您的机器信任的 CA 签名 - 它还有更多内容,但本质上就是它归结为的内容。

    那么,说了这么多,让我来回答你的问题:

    1) SslStream.AuthenticateAsServer(...) 仅在服务器端使用服务器 509 证书完成。在客户端,您必须调用SslStream.AuthenticateAsClient(serverName),服务器名称是您证书的 CNAME(通用名称)(例如:“domain.com”)

    2) 必须为客户端和服务器创建SslStream。您只需通过“包装”一个 TcpClient NetworkStream 来创建它(例如,但还有其他方法)

    服务器示例:

    // assuming an 509 certificate has been loaded before in an init method of some sort
    X509Certificate serverCertificate = X509Certificate2.CreateFromCertFile("c:\\mycert.cer"); // for illustration only, don't do it like this in production
    ...
    
    // assuming a TcpClient tcpClient was accepted somewhere above this code
    slStream sslStream = new SslStream(tcpClient.GetStream(), false);
    sslStream.AuthenticateAsServer(
                    serverCertificate,
                    false, 
                    SslProtocols.Tls, 
                    true);
    

    3) 不可以。通信在两端都被加密。所以双方必须使用SslStream。在客户端上使用receive()send() 会产生二进制加密数据。

    4) 否。客户端将回调方法传递给SslStream 创建,以验证服务器收到的证书。

    例子:

    // assuming a TcpClient tcpClient was connected to the server somewhere above this code
    SslStream sslStream = new SslStream(
                tcpClient.GetStream(),
                false,
                new RemoteCertificateValidationCallback(ValidateServerCertificate),
                null
                ); 
    sslStream.AuthenticateAsClient(serverName); // serverName: "domain.com" for example
    

    然后在您的代码中的其他地方:

    public static bool ValidateServerCertificate(
              object sender,
              X509Certificate certificate,
              X509Chain chain,
              SslPolicyErrors sslPolicyErrors)
        {
            if (sslPolicyErrors == SslPolicyErrors.None) {
                return true;
            }
    
            Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
    
            // refuse connection
            return false;
        }
    

    【讨论】:

    • 我可以在serverName中将服务器的IP地址作为字符串发送吗?
    • 是的,您可以(在 prod 中不推荐),但在这种情况下,您将遇到 SSL 故障等在您的客户端,只需始终在 ValidateServerCertificate() 函数中返回 true;或者做任何看起来适合你目的的事情。
    • 如果我使用sslStream.AuthenticateAsClient(serverIpAsString),为什么我会收到错误消息,因为无论如何 serverName 都被转换为 IPAddress?还有ValidateServerCertificate的值返回到哪里了?
    • 而且我也收到错误:根据验证程序,远程证书无效。我想修复它,而不是让它一直返回 true,因为这个解决方案需要安全。
    • 因为它就是这样运作的。我之前不正确,您不能使用 IP 作为服务器名称,因为服务器名称必须与证书上的名称匹配,句点。 IP 非常适合与服务器的初始连接,仅此而已。在这个 MSDN 页面上有一个完整的工作示例,适用于服务器和客户端——这实际上是我在上面发布的一些代码最初来自几年前的地方。 msdn.microsoft.com/en-us/library/… - 试一试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-02
    • 2018-02-24
    • 2018-12-19
    • 1970-01-01
    • 1970-01-01
    • 2015-08-10
    相关资源
    最近更新 更多