Ork*_*kar 17 c# sockets ssl https
我们有一个在服务器上运行的Web应用程序,它通过XDomainRequest发布http请求(因为IE9).
有许多客户端计算机具有通过套接字侦听器侦听端口的控制台应用程序.客户端使用IE9浏览器打开Web应用程序,当他们点击链接时,网页会发送以下请求:
" https:// localhost:portNumber/applicationName/doSomething "" https:// computerName:portNumber/applicationName/doSomething "" https:// ipAddress:portNumber/applicationName/doSomething "
第二和第三个请求用于控制其他用户计算机的应用程序.
问题是如果请求带有localhost,则控制台应用程序不会有关于读取传入数据和发送响应的问题.但是,如果请求附带计算机名称或IP地址,则浏览器会显示认证警告,并希望用户单击"继续访问此网站(不推荐)"链接.
我们想通过代码创建三个不同的证书.但即使使用其中三个的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;
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
你的安全人员是对的.你试图实现这一目标的方式不适用于SSL.
如果您有证书,则设置为对一个CN进行身份验证.所以,对于一个过于简单的例子.谷歌有证书.它会对https://*.google.com进行身份验证.这意味着任何google.com请求都会生成有效证书.而且你的浏览器很开心.
现在打开命令提示符,ping google.com.抓住IP地址(在我的情况下,它出现了216.58.210.14).输入https://216.58.210.14.您的浏览器抱怨该网站不安全等.原因是服务器可能与服务于您之前的请求的服务器相同,但根据证书,您获得该服务器的方式无效,因为CN不是谷歌. com,但是一个IP地址.
因此,如果您有一个需要连接到(例如)127.0.0.1,10.92.1.4和myserver.com的服务,您将需要一个对每种情况都有效的证书.
您遇到的证书警告实际上是名称不匹配错误,这表明 SSL 证书中的公用名称(域名)与用于访问网站/服务器的 URL/地址不匹配。
https://www.sslshopper.com/ssl-certificate-name-mismatch-error.html
在您的使用场景中,您可能希望放弃 localhost 和 IP 地址,转而采用利用计算机名称的简单域模型。(例如computerName.someDomain.com)
然后,您可以获得一个通配符证书(例如*.someDomain.com),该证书可用于验证进程间通信。
https://www.sslshopper.com/best-ssl-wildcard-certificate.html