c# SSL TCPServer 停留在 SsLStream.AuthenticateAsServer()
c# SSL TCPServer stuck at SsLStream.AuthenticateAsServer()
故事情节:
我想用 c# 制作我自己的网络服务器(第一次尝试)。一切顺利(我使用 Visual Studio 对应用程序进行编码 ,并使用 Firefox 检查 是否正确)并且我设法做到了制作一个基本的 TCPServer。当我试图向它添加 SSL 支持时,我遇到了一个问题。
- 过去 7 天我一直在尝试使用 SSLStream.AuthenticateAsServer([自签名证书])作为支持 SSL 的 TcpServer 进行身份验证
问题:
当我从我心爱的 Firefox 收到 [Upgrade-Insecure-Requests: 1] 时,我正在尝试 [SSLStream.AuthenticateAsServer([自签名证书])]。这样做 我的代码卡住了(但没有 freeze/crash) 在这一行,而 我的 Firefox 只是永远加载 似乎没有给我回复。
代码:
启动我的服务器
TCPServer.ServerStart(8080);
(侦听器正在我的 TCPServer class 中定义)
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 没有任何了解 I used this example-code)
Upgrade-Insecure-Requests
并不意味着服务器可以加密 当前 连接。 Firefox 仍然需要未加密的 HTTP/1.x 响应。但是这个响应可以重定向到另一个URL——也许在另一个端口上——SSL将从一开始就被启用。
请参阅升级不安全请求中的示例 8
规范.
我做到了!问题是(在我的线程中)我使用的是 X509Certificate public-made 证书,里面没有密钥,而不是 X509Certificate2 private-cert 里面有密钥。这就是为什么我的代码在 SslStream.AuthenticateAsServer(); 处挂起。 @Vasiliy Faronov 回答对我也很有帮助(我需要在端口 443 上添加一个 307 header),thx.
无论如何,这是一个如何通过 tcp-level 中的 https 将 index.html 发送到您的网络浏览器的示例:
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();
}
}
}
故事情节:
我想用 c# 制作我自己的网络服务器(第一次尝试)。一切顺利(我使用 Visual Studio 对应用程序进行编码 ,并使用 Firefox 检查 是否正确)并且我设法做到了制作一个基本的 TCPServer。当我试图向它添加 SSL 支持时,我遇到了一个问题。
- 过去 7 天我一直在尝试使用 SSLStream.AuthenticateAsServer([自签名证书])作为支持 SSL 的 TcpServer 进行身份验证
问题:
当我从我心爱的 Firefox 收到 [Upgrade-Insecure-Requests: 1] 时,我正在尝试 [SSLStream.AuthenticateAsServer([自签名证书])]。这样做 我的代码卡住了(但没有 freeze/crash) 在这一行,而 我的 Firefox 只是永远加载 似乎没有给我回复。
代码:
启动我的服务器
TCPServer.ServerStart(8080);
(侦听器正在我的 TCPServer class 中定义)
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 没有任何了解 I used this example-code)
Upgrade-Insecure-Requests
并不意味着服务器可以加密 当前 连接。 Firefox 仍然需要未加密的 HTTP/1.x 响应。但是这个响应可以重定向到另一个URL——也许在另一个端口上——SSL将从一开始就被启用。
请参阅升级不安全请求中的示例 8 规范.
我做到了!问题是(在我的线程中)我使用的是 X509Certificate public-made 证书,里面没有密钥,而不是 X509Certificate2 private-cert 里面有密钥。这就是为什么我的代码在 SslStream.AuthenticateAsServer(); 处挂起。 @Vasiliy Faronov 回答对我也很有帮助(我需要在端口 443 上添加一个 307 header),thx.
无论如何,这是一个如何通过 tcp-level 中的 https 将 index.html 发送到您的网络浏览器的示例:
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();
}
}
}