Abbiamo un'applicazione Web in esecuzione sul server e pubblica richieste http tramite XDomainRequest (a causa di IE9).La certificazione SSL funziona con localhost ma non con il nome del computer o IP
Ci sono molti computer client che hanno un'applicazione di console in ascolto su una porta tramite listener di socket. I client di applicazioni web aperto con le loro browser IE9 e quando fanno clic su un link, la pagina web invia le richieste del genere:
"https://localhost:portNumber/applicationName/doSomething" "https://computerName:portNumber/applicationName/doSomething" "https://ipAddress:portNumber/applicationName/doSomething"
La seconda e terza richieste sono fatto per console applicazioni dei computer degli altri utenti.
Il problema è che se le richieste arrivano con localhost, l'applicazione della console non ha problemi a leggere i dati in arrivo e ad inviare la risposta. Ma se la richiesta viene fornita con il nome del computer o l'indirizzo IP, il browser mostra l'avviso di certificazione e vuole che l'utente faccia clic sul link "Continua su questo sito web (non consigliato)".
Abbiamo pensato di creare tre certificati diversi tramite codice. Ma anche usando sslstream con tre di questi è possibile, non possiamo decidere di selezionare la vera certificazione perché prima facciamo l'autenticazione e poi riceviamo i dati. Quindi, quando intercettiamo la richiesta in arrivo, l'autenticazione deve essere già eseguita.
Un altro modo è forzare il listener di socket o sslstream a comportarsi tutte queste tre richieste come se fossero localhost. Quindi per ognuna l'autenticazione sarà fatta come localhost. Ma non sono riuscito a trovare un modo per farlo.
Ecco il codice. Fornisco il codice perché forse c'è un uso errato di 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;
}
}
Questo perché il CN del certificato è localhost. Dovrai utilizzare un certificato appropriato che corrisponda al nome host della richiesta in modo che la convalida funzioni. –
Diciamo che il nome del computer che esegue il sito web è server1. Il certificato avrà CN = server1 informazioni? –
Ma quando apro il file PFX con certmgr vedo che CN è impostato su qualcosa di diverso da localhost. –