具有自签名 SSL 和自托管的 SignalR
在研究中碰碰运气,但到目前为止没有任何乐趣.
Tried my luck at research, but so far no joy.
我想将 SignalR javascript 客户端连接到绑定到自签名 SSL 证书的自托管 SignalR Windows 服务.
I would like to connect a SignalR javascript client to a self-hosted SignalR Windows Service binding to a self-signed SSL certificate.
我的应用程序在 http 上运行良好,但是当 Owin WebApplication 开始使用 https 时,客户端反复断开连接.
My application works quite well over http, but the client repetitively disconnects when the Owin WebApplication starts using https.
这是我为使用 SSL 配置 SignalR 所做的工作.
Here is what I've done to configure SignalR with SSL.
- 使用 IIS 创建自签名证书
- 将证书导入 mmc 中的受信任根证书颁发机构(不确定是否有帮助)
运行 NETSH 命令将 SSL 绑定到端口 8080
- Created a Self-Signed certificate using IIS
- Imported the certificate into the Trusted Root Certification Authorities in the mmc (not sure if that helped)
Ran NETSH command to bind SSL to port 8080
netsh http add sslcert ipport=0.0.0.0:8080 certhash=123456f6790a35f4b017b55d09e28f7ebe001bd appid={12345678-db90-4b66-8b01-88f7af2e36bf}
在自托管的 HubConnection 实例中添加代码以添加这样的导出 SSL(尽管这应该无关紧要,因为客户端无法连接):
Added code in self-hosted HubConnection instances to add exported SSL like this (though this shouldn't matter because it's the client that cannot connect):
if (File.Exists("MyCert.cer")
&& Settings.GetSetting(Settings.Setting.SrProtocol).Equals("https", StringComparison.InvariantCultureIgnoreCase))
connection.AddClientCertificate(X509Certificate.CreateFromCertFile("MyCert.cer"));
使用 https 启动 Owin WebApplication(这应该在 http.sys 中创建绑定)
Starting Owin WebApplication using https (this should create the binding in http.sys)
string registerUrl = string.Format("{0}://SOME.WHERE.COM:{1}", Service.Server.SrProtocol, Service.Server.SrPort);
WebApp.Start<StartUp>(registerUrl);
在 SignalR 2.0 文档中,它说:
In the SignalR 2.0 documentation, it says:
要启动 Web 服务器,请调用 WebApplication.Start(endpoint).您现在应该可以在浏览器中导航到端点/信号/集线器.
To start the web server, call WebApplication.Start(endpoint). You should now be able to navigate to endpoint/signalr/hubs in your browser.
当我浏览到 URL http://SOME.WHERE.COM:8080/signalr/hubs我成功接收到驱动 SignalR 的 javascript.
When I browse to the URL http://SOME.WHERE.COM:8080/signalr/hubs I am successful receiving the javascript that drives SignalR.
当我浏览到 URL https://SOME.WHERE.COM:8080/signalr/hubs我没有成功,并且使用 FF 收到与服务器的连接已重置".
When I browse to the URL https://SOME.WHERE.COM:8080/signalr/hubs I am unsuccessful and I receive "The connection to the server was reset" using FF.
我考虑过的一些额外要点:
Some additional points I've considered:
NETSH SHOW 表示网址已注册
NETSH SHOW indicates the url is registered
URL group ID: E300000240000022
State: Active
Request queue name: Request queue is unnamed.
Properties:
Max bandwidth: inherited
Max connections: inherited
Timeouts:
Timeout values inherited
Number of registered URLs: 1
Registered URLs: HTTPS://SOME.WHERE.COM:8080/
NETSH SHOW 表示 SSL 证书绑定到 8080:
NETSH SHOW indicates the SSL certificate is bound to 8080:
IP:port : 0.0.0.0:8080
Certificate Hash : 123456f6790a35f4b017b55d09e28f7ebe001bd
Application ID : {12345678-db90-4b66-8b01-88f7af2e36bf}
Certificate Store Name : (null)
Verify Client Certificate Revocation : Enabled
Verify Revocation Using Cached Client Certificate Only : Disabled
Usage Check : Enabled
Revocation Freshness Time : 0
URL Retrieval Timeout : 0
Ctl Identifier : (null)
Ctl Store Name : (null)
DS Mapper Usage : Disabled
Negotiate Client Certificate : Disabled
非常感谢任何帮助!
我相信它现在对我有用.以下是我为使事情顺利进行而采取的步骤的简要说明:
I believe its all working for me now. Here is a run down of the steps I took to get things flowing:
SSL 说明
SSL &SignalR (Owin WebApplication) 需要将证书绑定到端口.
SSL & SignalR (Owin WebApplication) requires binding a certificate to a port.
- 使用 IIS 生成自签名证书,这应该将证书放入 CERTMGR 中的 LOCAL COMPUTER > Personal > Certificates 文件夹
- 在 CERTMGR 中 shift+drag 证书到 LOCAL COMPUTER > Trusted Root Certification Authorities > Certificates 文件夹,应该在那里复制一份
运行以下命令将 SSL 证书绑定到 0.0.0.0:8080
- Use IIS to generate an self-signed cert, this should place the certificate into the LOCAL COMPUTER > Personal > Certificates folder in CERTMGR
- In CERTMGR shift+drag certificate to LOCAL COMPUTER > Trusted Root Certification Authorities > Certificates folder, which should make a copy of it there
Run the following command to bind the SSL certificate to 0.0.0.0:8080
netsh http add sslcert ipport=0.0.0.0:8080 certhash=123456f6790a35f4b017b55d09e28f7ebe001bd appid={12345678-db90-4b66-8b01-88f7af2e36bf}
netsh http show urlacl > D:\urlacl.txt
输出:
Reserved URL : https://*:8080/
User: SOMEWHERE\Administrator
Listen: Yes
Delegate: No
SDDL: D:(A;;GX;;;S-1-5-21-138209071-46972887-2260295844-1106)
运行以下 NETSH 命令,将端口 8080 的所有 IP 地址保留给 My Service 应用程序 ID 和服务帐户
Run the following NETSH command to reserve all IP addresses for port 8080 to the My Service application ID and service account
netsh http add urlacl url=https://*:8080/ user=SOMEWHERE\Administrator listen=yes
netsh http show sslcert > D:\sslcert.txt
输出:
IP:port : 0.0.0.0:8080
Certificate Hash : 123456f6790a35f4b017b55d09e28f7ebe001bd
Application ID : {12345678-db90-4b66-8b01-88f7af2e36bf}
Certificate Store Name : (null)
Verify Client Certificate Revocation : Enabled
Verify Revocation Using Cached Client Certificate Only : Disabled
Usage Check : Enabled
Revocation Freshness Time : 0
URL Retrieval Timeout : 0
Ctl Identifier : (null)
Ctl Store Name : (null)
DS Mapper Usage : Disabled
Negotiate Client Certificate : Disabled
更新 MyServices.exe.config 文件以使用 https 协议(这些是 appSetting 键,用于在 My Service 启动时动态设置 SignalR 的协议和端口)
Update the MyServices.exe.config file to use https protocol (These are appSetting keys used to dynamically set the protocol and port of SignalR when My Service starts)
<add key="SrProtocol" value="https" />
<add key="SrPort" value="8080" />
使用 NETSTAT START 命令启动我的服务
Start the My Service using the NETSTAT START command
运行以下NETSH命令显示服务状态正在占用注册的url
Run the following NETSH command to show the service state is occupying the registered url
netsh http show servicestate > D:\servicestate.txt
输出:
Server session ID: C300000320000039
Version: 2.0
State: Active
Properties:
Max bandwidth: 4294967295
Timeouts:
Entity body timeout (secs): 120
Drain entity body timeout (secs): 120
Request queue timeout (secs): 120
Idle connection timeout (secs): 120
Header wait timeout (secs): 120
Minimum send rate (bytes/sec): 150
URL groups:
URL group ID: C600000340000138
State: Active
Request queue name: Request queue is unnamed.
Properties:
Max bandwidth: inherited
Max connections: inherited
Timeouts:
Timeout values inherited
Number of registered URLs: 1
Registered URLs:
HTTPS://*:8080/
我的应用程序不依赖于 IIS,但是一旦我使用 IIS 临时创建绑定到我的 SSL 证书的端口,我的应用程序就开始工作,我能够检查 NETSH 服务状态以查看 IIS 是如何做到的.从那以后,我放弃了 IIS 绑定并浏览了安装说明,但仍然成功.
My application does NOT depend on IIS, but once I used IIS to temporarily create a port binding to my SSL certificate, my application started to work, and I was able to inspect the NETSH servicestate to see how IIS does it. I have since dropped the IIS binding and ran through the setup notes, and still have success.
我的 Owing 初创公司看起来像这样:
My Owing startup looks somethign like this:
private void configureMessaging()
{
string registerUrl = string.Format("{0}://*:{1}", Service.Server.SrProtocol, Service.Server.SrPort);
try
{
#if DEBUG
//System.Diagnostics.Debugger.Launch();
#endif
// Starts an owin web application to host SignalR, using the protocol and port defined.
WebApp.Start<StartUp>(registerUrl);
}
catch (Exception ex)
{
Logger.Logs.Log(string.Format("Failed to configure messaging. Exception: {0}", ex.RecurseInnerException()), LogType.Error);
if (ex is HttpListenerException || ex.InnerException is HttpListenerException)
{
try
{
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "netsh.exe";
p.StartInfo.Arguments = string.Format("netsh http delete urlacl url={0}"
, registerUrl
);
p.Start();
p.StandardOutput.ReadToEnd();
p.WaitForExit();
}
catch (Exception exP)
{
Logger.Logs.Log(string.Format("Failed to delete urlacl {0}. Exception: {1}"
, registerUrl
, exP.RecurseInnerException()
)
, LogType.Error
)
;
retries = 5;
}
}
if (retries < 5)
{
retries++;
Logger.Logs.Log(string.Format("Attempting to configure messaging again. Attempt No. {0}", retries), LogType.Warn);
Thread.Sleep(1000);
configureMessaging();
}
else
Logger.Logs.Log(string.Format("Exceeded total number of retries to configure messaging.", retries), LogType.Error);
}
}
自托管 HubConnetion 实例如下所示:
And self-hosted HubConnetion instances look like this:
public IHubProxy MyHubProxy
{
get
{
if (this._MyHubProxy == null)
{
var connection = new HubConnection(string.Format("{0}://{1}:{2}/"
, Settings.GetSetting(Settings.Setting.SrProtocol)
, MyHub.GetLocalhostFqdn(null)
, Settings.GetSetting(Settings.Setting.SrPort)
)
)
;
this._MyHubProxy = connection.CreateHubProxy("MyHub");
if (File.Exists("My.cer")
&& Settings.GetSetting(Settings.Setting.SrProtocol).Equals("https", StringComparison.InvariantCultureIgnoreCase))
connection.AddClientCertificate(X509Certificate.CreateFromCertFile("My.cer"));
connection.Start().Wait();
}
return this._MyHubProxy;
}
}
这里的代码比相关的要多一些,但希望它可能有所帮助!
There is a little more code here than relevant, but hopefully it may be of help!