c # SSL TCPServer застрял в SsLStream.AuthenticateAsServer () - PullRequest
3 голосов
/ 20 марта 2019

Сюжетная:

Я хотел создать свой собственный веб-сервер на c # (первая попытка). Все прошло хорошо (я использовал Visual Studio для кодирования приложения и Firefox для проверки , правильно ли я поступил), и мне удалось создать базовый TCPServer. Когда я пытался добавить поддержку SSL, я столкнулся с проблемой.

  • Я пытался аутентифицироваться как TcpServer с поддержкой SSL с использованием SSLStream.AuthenticateAsServer ([самозаверяющий сертификат]) в течение последних 7 дней

Проблема:

Когда я получаю [Upgrade-Insecure-Requests: 1] от моего любимого Firefox, я пытаюсь [SSLStream.AuthenticateAsServer ([самозаверяющий сертификат])]. При этом мой код застрял (но не зависает / не падает) в этой строке, в то время как мой Firefox просто загружается вечно , не отправляя мне ответ.

Код:


запуск моего сервера
TCPServer.ServerStart(8080);


(слушатель определяется в моем классе TCPServer)
internal static TcpListener listener;

async internal static void ServerStart(int port)
    {
        if (listener == null)
        {
            listener = new TcpListener(IPAddress.Any, port);
        }
        listener.Start();

        //clients
        await Task.Run(()=> SucheNachBesuchern());
        listener.Stop();
    }


прием клиентов
private static void SucheNachBesuchern(){
        TcpClient Besucher;

        while (true)
        {
            Besucher = listener.AcceptTcpClient();
            ThreadPool.QueueUserWorkItem(ThreadProzess, Besucher);
        }
    }


обработка принятых клиентов
private static void ThreadProzess(object Besucher) {
        TcpClient besucher = (TcpClient)Besucher;
        Abfertige(besucher);
        besucher.Close();
        besucher.Dispose();
    }

private static void Abfertige(TcpClient Besucher)
    {
        //Reading the Request
        StreamReader Auftrag = new StreamReader(Besucher.GetStream());
        List<String> AuftragNachricht= new List<String>();
        while (Auftrag.Peek()!=-1) {
            AuftragNachricht.Add(Auftrag.ReadLine());
        }

        //Anfrage = request Class with bool Anfrage.SSLAnfrage being true
        //if the request contains 'Upgrade-Insecure-Requests: 1'
        Anfrage Anfrage = Anfrage.VerarbeiteAuftrag(AuftragNachricht);

        if (Anfrage.SSLAnfrage)// = if([request conatined 'Upgrade-Insecure-Requests: 1'])
        {
            //opening an SslStream to the TcpClient Besucher
            SslStream SSLStream = new SslStream(Besucher.GetStream(), false);
            try
            {
                //Authenticating as TcpServer supporting SSL !CODE IS STUCK AT THIS LINE!
                SSLStream.AuthenticateAsServer([SELFSINGEDX509CERTIFICATE.cer using openssl pkcs12], clientCertificateRequired: false, enabledSslProtocols: System.Security.Authentication.SslProtocols.Default, checkCertificateRevocation: false);

                //set timeouts for read and write
                SSLStream.ReadTimeout = 5000;
                SSLStream.WriteTimeout = 5000;

                //tryig to catch my Firefox as new client on SSL port 443
                TcpListener SSLListener = new TcpListener(IPAddress.Parse("192.168.178.72"), 443); 
                SSLListener.Start();
                TcpClient SSLBesucher = SSLListener.AcceptTcpClient();
                Debug.WriteLine("I'VE GOT A CLIENT HERE!!!!111");
            }
            catch (Exception Error) {
                Debug.WriteLine($"---Error gefangen: {Error.ToString()}");
            }
        }//[...more Code]


(Из-за отсутствия каких-либо знаний по SSL я использовал этот пример кода )

Ответы [ 2 ]

1 голос
/ 22 марта 2019

Upgrade-Insecure-Requests не означает, что сервер может шифровать текущее соединение .Firefox по-прежнему ожидает незашифрованный ответ HTTP / 1.x.Но этот ответ может перенаправить его на другой URL - возможно, на другой порт - где SSL будет включен с самого начала.

См. пример 8 в спецификации небезопасных запросов на обновление .

0 голосов
/ 23 марта 2019

Я сделал это! Проблема заключалась в том, что (в моей ветке) я использовал публичный сертификат X509Certificate без ключей вместо закрытого сертификата X509Certificate2 с ключами в нем. Вот почему я получил зависания в своем коде в SslStream.AuthenticateAsServer () ;. @ Vasiliy Faronov Ответ мне тоже очень помог (мне нужно было добавить заголовок 307 в порт 443), спасибо.

В любом случае, вот пример того, как отправить index.html вашему браузеру через https на уровне tcp:

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace SSLTEST
{
    class Program
    {
        static X509Certificate2 CER = new X509Certificate2("privatecert.cer","pass");// Has to be a private X509cert with key
        static void Main(string[] args)
        {
            TcpListener listener = new TcpListener(IPAddress.Parse("192.168.178.72"), 443);
            listener.Start();
            TcpClient client = listener.AcceptTcpClient();
            Console.WriteLine("client accepted");

            SslStream stream = new SslStream(client.GetStream());
            stream.AuthenticateAsServer(CER, false, System.Security.Authentication.SslProtocols.Tls12, false);
            Console.WriteLine("server authenticated");


            Console.WriteLine("----client request----");
            Decoder decoder = Encoding.UTF8.GetDecoder();
            StringBuilder request = new StringBuilder();
            byte[] buffer = new byte[2048];
            int bytes = stream.Read(buffer, 0, buffer.Length);

            char[] chars = new char[decoder.GetCharCount(buffer, 0, buffer.Length)];
            decoder.GetChars(buffer, 0, bytes, chars, 0);

            request.Append(chars);

            Console.WriteLine(request.ToString());
            Console.WriteLine("---------------------");

            String method = request.ToString().Split('\n')[0].Split(' ')[0];
            String requestedfile = request.ToString().Split('\n')[0].Split(' ')[1];
            if (method == "GET" & requestedfile == "/")
            {
                FileStream datastream = new FileInfo(Environment.CurrentDirectory+@"\"+"index.html").OpenRead();
                BinaryReader datareader = new BinaryReader(datastream);
                byte[] data = new byte[datastream.Length];
                datastream.Read(data, 0, data.Length);
                datastream.Close();

                StringBuilder header = new StringBuilder();
                header.AppendLine("HTTP/1.1 200 OK");
                header.AppendLine("Content-Length: "+data.Length);
                header.AppendLine();

                List<Byte> responsedata = new List<byte>();
                responsedata.AddRange(Encoding.ASCII.GetBytes(header.ToString()));
                responsedata.AddRange(data);

                stream.Write(responsedata.ToArray(), 0, responsedata.ToArray().Length);
                Console.WriteLine("- response sent");
            }

            stream.Close();
            Console.WriteLine("done!");
            Console.Read();
        }
    }
}
...