Подтвердить что ты не робот

Сертификация SSL работает с localhost, но не с именем компьютера или ip

У нас есть веб-приложение, работающее на сервере, и оно отправляет HTTP-запросы через XDomainRequest (из-за IE9).

Существует множество клиентских компьютеров, в которых консольное приложение прослушивается через порт через прослушиватель сокетов. Клиенты открывают веб-приложение с помощью своих IE9, и когда они нажимают на ссылку, веб-страница отправляет такие запросы:

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

Второй и третий запросы выполняются для консольных приложений компьютеров других пользователей.

Проблема в том, что если запросы поставляются с localhost, консольное приложение не имеет проблем с чтением входящих данных и отправкой ответа. Но если запрос поставляется с именем компьютера или IP-адресом, браузер показывает предупреждение о сертификации и хочет, чтобы пользователь нажал Msgstr "Продолжить ссылку на этот сайт (не рекомендуется).

Мы думали создать три разных сертификата через код. Но даже использование sslstream с тремя из них возможно, мы не сможем выбрать истинную сертификацию, потому что сначала делаем аутентификацию, а затем получаем данные. Поэтому, когда мы получаем входящий запрос, аутентификация должна быть уже выполнена.

Другой способ - заставить прослушиватель сокетов или sslstream вести все эти три запроса, как если бы они были localhost. Таким образом, для каждой аутентификации будет выполняться как localhost. Но я не мог найти фактического пути для этого.

Вот код. Я даю код, потому что, возможно, есть неправильное использование SslStream.

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;
    }
}
4b9b3361

Ответ 1

Предупреждение о сертификате, которое вы встречаете, действительно является ошибкой несоответствия имени, что указывает на то, что общее имя (имя домена) в сертификате 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

Ответ 2

Ваш защитник прав. То, как вы пытаетесь это сделать, не работает с SSL.

Если у вас есть сертификат, он настроен на аутентификацию одного CN. Итак, для упрощенного примера. У Google есть сертификат. Он аутентифицирует 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), вам понадобится сертификат, действительный для каждого случая.

Ответ 3

Я не уверен, что означает ваш "https://computerName:portNumber/applicationName/doSomething". Поэтому не уверен, что вы используете право сертификата или правильно ли используете пути или соединение, которые вы просматриваете или используете в коде. https://technet.microsoft.com/en-us/library/dd891009.aspx

Он может получить доступ к любому протоколу, не ограниченному TCP. https://technet.microsoft.com/en-us/library/cc784450(v=ws.10).aspx

  • Подстановочные SSL-сертификаты позволяют администраторам защищать неограниченное количество поддоменов в одном домене с помощью одного сертификата SSL. Сертификат SSL WildCard выдается на адрес *.yourdomain.com, предоставляя преимущества экономии затрат при покупке многочисленных SSL-сертификатов для каждого поддомена, а также только для использования одного IP-адреса.
  • Типичные SSL-сертификаты защищают только одно Полноценное доменное имя. Сертификаты унифицированных коммуникаций позволяют назначать несколько имен хостов, называемых альтернативными именами субъектов или SAN, в одном сертификате. Для обеспечения полной гибкости многодоменный SSL-сертификат позволяет использовать поле "Альтернативное имя субъекта" (SAN), чтобы вы могли защитить до 100 различных доменных имен, поддоменов или общедоступных IP-адресов, используя один сертификат SSL и требуя только одного IP-адрес.

** Значение должно точно совпадать с именем хоста или именем домена, к которому вы обращаетесь. В противном случае вы все равно получите ошибки сертификата браузера после того, как сертификат будет импортирован и доверен. Например: если вы ранее использовали http://101.10.10.1:9000/ для доступа к сайту, а общее имя нового сертификата было "mydomain", тогда ярлык должен быть обновлен до http://mydomain:9000/; если вы создали сертификат для mydomain:9000. Во-вторых, используйте имя хоста или CNAME, по которым вы будете обращаться к серверу. Это очень важно. Если ваше веб-серверное имя реального хоста - это mysubdomain.mydomain.com, но люди будут использовать www.mydomain.com для обращения к этому полю, а затем использовать последнее имя для ответа на вопрос "Общее имя" (CNAME).

** Проверьте, можете ли вы подключиться с помощью openssl s_time -connect remote.host:443 (используйте определенные команды ssl для устранения неполадок, я цитирую openssl) или openssl s_time -connect remote.host:443 -www /test.html -new ** Если у вас нет доступного для использования веб-сервера с поддержкой SSL, вы можете эмулировать его с помощью параметра s_server.

# on one host, set up the server (using default port 4433) openssl s_server -cert mycerti.pem -www # on second host (or even the same one), run s_time openssl s_time -connect mydomain:9001 -www / -new -ssl3

или

# on second host (or even the same one), run s_time openssl s_time -connect mydomain:9001 -www / -new -ssl3 ** Проверьте, используется ли сертификат? $ openssl s_client -connect [ip_or_dns_name]:[port] $ man s_client

Ответ 4

Решение, которое я предлагаю, имеет предположение:

  • сайт размещен на IIS

  • вы можете получить доступ к приложению по имени машины по сети без каких-либо проблем.

  • вам не нужно получать доступ к webapp в Интернете (для этого вам потребуется cetificate от сертифицированных авторитетов).

Try:

  • Создайте самоподписанный сертификат IIS как:

    я. Откройте IIS, выберите Сертификаты сервера, например: введите описание изображения здесь

    II. Создайте собственный сертификат: введите описание изображения здесь

    III. настроить веб-сайт для использования этого сертификата, например:

    • выберите веб-сайт, нажмите привязки.

    • нажмите изменить привязки для https

введите описание изображения здесь

IV. Изменить привязку сайта для использования созданного вами сертификата:

введите описание изображения здесь

Теперь вы можете получить доступ к вашему приложению с именем машины.

Тот же процесс, который вы можете повторить для сертификатов домена для Интернета, но который требует сертификата, зарегистрированного/предоставленного некоторыми сертифицированными полномочиями.

Обратите внимание, что теперь для доступа к приложению можно использовать Имя машины как в локальной сети, так и в сети. Поскольку сертификат выдается для имени одного узла/совместного домена, используйте вместо имени localhost локальное имя машины.