首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >SSL认证适用于本地主机,但不适用于计算机名称或ip

SSL认证适用于本地主机,但不适用于计算机名称或ip
EN

Stack Overflow用户
提问于 2015-12-14 18:21:29
回答 2查看 15.4K关注 0票数 17

我们有一个运行在服务器上的web应用程序,它通过XDomainRequest (由于IE9)发布http请求。

有许多客户端计算机都有一个控制台应用程序,通过套接字侦听器监听端口。客户端使用其IE9浏览器打开web应用程序,当他们单击链接时,web页面会发送如下请求:

"https://localhost:portNumber/applicationName/doSomething“"https://computerName:portNumber/applicationName/doSomething”"https://ipAddress:portNumber/applicationName/doSomething

向其他用户的计算机的控制台应用程序发出第二和第三个请求。

问题是,如果请求来自localhost,则控制台应用程序在读取传入数据和发回响应方面不会出现问题。但是,如果请求带有计算机名称或ip地址,则浏览器会显示认证警告,并希望用户单击“继续访问此网站(不推荐)”链接。

我们认为通过代码创建三种不同的证书。但是,即使使用sslstream和其中的三个,我们也不能决定选择真正的认证,因为我们首先进行身份验证,然后接收数据。因此,当我们捕获传入请求时,身份验证必须已经完成。

另一种方法是强制套接字侦听器或sslstream将所有这三个请求都当作本地主机。因此,对于每一个,都将作为localhost进行身份验证。但我找不到一种实际的方法。

下面是代码。我给出代码是因为可能有一些SslStream的错误用法。

代码语言:javascript
复制
using System;
using System.Net.Sockets;
using System.Net;
using System.Configuration;
using System.Security.Cryptography.X509Certificates;
using System.Windows.Forms;
using System.IO;
using System.Net.Security;
using System.Security.Authentication;
using System.Threading;
using System.Text;

namespace StackOverFlowProject
{
    class StackOverFlowSample
    {
        private static ManualResetEvent _manualResetEvent = new ManualResetEvent(false);
        private static X509Certificate _cert = null;

        static void Main(string[] args)
        {
            StackOverFlowSample stackOverFlowSample = new StackOverFlowSample();
            stackOverFlowSample.StartListening();
        }

        private void StartListening()
        {
            GetCertificate();

            IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 1234);

            if (localEndPoint != null)
            {
                Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                if (listener != null)
                {
                    listener.Bind(localEndPoint);
                    listener.Listen(10);

                    Console.WriteLine("Socket listener is running. Waiting for requests...");

                    listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
                }
            }
        }

        private static void GetCertificate()
        {
            byte[] pfxData = File.ReadAllBytes(Application.StartupPath + @"\" + "localhost.pfx");

            _cert = new X509Certificate2(pfxData, "password", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
        }


        private void AcceptCallback(IAsyncResult result)
        {
            Socket listener = null;
            Socket handler = null;
            StateObject state = null;
            SslStream sslStream = null;

            _manualResetEvent.Set();

            listener = (Socket)result.AsyncState;

            handler = listener.EndAccept(result);

            state = new StateObject();

            if (handler.RemoteEndPoint != null)
            {
                state.clientIP = ((IPEndPoint)handler.RemoteEndPoint).Address.ToString();
            }

            sslStream = new SslStream(new NetworkStream(handler, true));
            sslStream.AuthenticateAsServer(_cert, false, SslProtocols.Tls, true);

            sslStream.ReadTimeout = 100000;
            sslStream.WriteTimeout = 100000;

            state.workStream = sslStream;

            if (state.workStream.IsAuthenticated)
            {
                state.workStream.BeginRead(state.buffer, 0, StateObject.BufferSize, ReceiveCallback, state);
            }

            listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
        }

        private void ReceiveCallback(IAsyncResult result)
        {
            StateObject stateObject = null;
            SslStream sslStreamReader = null;

            byte[] byteData = null;

            stateObject = (StateObject)result.AsyncState;
            sslStreamReader = stateObject.workStream;

            int byteCount = sslStreamReader.EndRead(result);

            Decoder decoder = Encoding.UTF8.GetDecoder();
            char[] chars = new char[decoder.GetCharCount(stateObject.buffer, 0, byteCount)];
            decoder.GetChars(stateObject.buffer, 0, byteCount, chars, 0);
            stateObject.sb.Append(chars);

            if (byteCount > 0)
            {
                stateObject.totalReceivedBytes += byteCount;

                string[] lines = stateObject.sb.ToString().Split('\n');

                if (lines[lines.Length - 1] != "<EOF>")
                {
                    // We didn't receive all data. Continue reading...
                    sslStreamReader.BeginRead(stateObject.buffer, 0, stateObject.buffer.Length, new AsyncCallback(ReceiveCallback), stateObject);
                }
                else
                {
                    Console.WriteLine("We received all data. Sending response...");

                    byteData = Encoding.UTF8.GetBytes("Hello! I received your request!");

                    string httpHeaders = "HTTP/1.1" + "\r\n"
                                    + "Cache-Control: no-cache" + "\r\n"
                                    + "Access-Control-Allow-Origin: *" + "\r\n"
                                    + "\r\n";

                    byte[] byteHttpHeaders = Encoding.UTF8.GetBytes(httpHeaders);

                    byte[] concat = new byte[byteHttpHeaders.Length + byteData.Length];
                    Buffer.BlockCopy(byteHttpHeaders, 0, concat, 0, byteHttpHeaders.Length);
                    Buffer.BlockCopy(byteData, 0, concat, byteHttpHeaders.Length, byteData.Length);

                    stateObject.sslStreamReader = sslStreamReader;

                    sslStreamReader.BeginWrite(concat, 0, concat.Length, new AsyncCallback(SendCallback), stateObject);
                }
            }
        }

        private void SendCallback(IAsyncResult ar)
        {
            SslStream sslStreamSender = null;

            StateObject stateObject = (StateObject)ar.AsyncState;

            sslStreamSender = stateObject.sslStreamReader;
            sslStreamSender.EndWrite(ar);

            Console.WriteLine(stateObject.totalReceivedBytes.ToString() + " bytes sent to " + stateObject.clientIP + " address");

            sslStreamSender.Close();
            sslStreamSender.Dispose();
        }

    }

    public class StateObject
    {
        public SslStream workStream = null;

        public SslStream sslStreamReader = null;

        public const int BufferSize = 1024;
        public byte[] buffer = new byte[BufferSize];
        public StringBuilder sb = new StringBuilder();

        public string clientIP = "";

        public int totalReceivedBytes = 0;
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-12-23 01:58:19

您遇到的证书警告实际上是名称不匹配错误,这表明SSL证书中的通用名称(域名)与用于访问网站/服务器的URL/地址不匹配。

https://www.sslshopper.com/ssl-certificate-name-mismatch-error.html

在您的使用方案中,您可能希望从本地主机和ip地址过渡到利用计算机名称的简单域模型。(例如computerName.someDomain.com)

然后,您可以获得可用于验证进程间通信的通配符证书(例如*.someDomain.com)。

https://www.sslshopper.com/best-ssl-wildcard-certificate.html

票数 3
EN

Stack Overflow用户

发布于 2015-12-17 20:25:19

你的保安是对的。您试图实现这一点的方式在SSL中不起作用。

如果您有证书,则设置为对一个CN进行身份验证。所以,对于一个过于简单的例子。谷歌有一个证书。它对https://*.google.com进行身份验证。这意味着任何对google.com的请求都会被视为具有有效的证书。而且你的浏览器也很好用。

现在打开命令提示符,ping google.com。获取ip地址(在我的示例中为216.58.210.14)。输入https://216.58.210.14。您的浏览器抱怨站点不安全等。原因是服务器可能是为您之前的请求提供服务的服务器,但根据证书,您访问它的方式是无效的,因为CN不是google.com,而是IP地址。

因此,如果你有一个服务需要连接到(例如) 127.0.0.1,10.92.1.4和myserver.com,你将需要一个对每种情况都有效的证书。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34264559

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档