检查 asp.net mvc 4 应用程序中的 ssl 协议、密码和其他属性

Posted

技术标签:

【中文标题】检查 asp.net mvc 4 应用程序中的 ssl 协议、密码和其他属性【英文标题】:Check ssl protocol, cipher & other properties in an asp.net mvc 4 application 【发布时间】:2014-07-29 05:57:58 【问题描述】:

出于合规性原因,我们必须在我们的网络服务器上关闭对某些密码和 SSL2 的支持。这不是一个真正的问题,但我们也想通知他们,在他们成功登录网站后,我们建议在他们的浏览器中打开 TLS 1.2,以防他们尚未使用 TLS 1.2 连接到服务器。所以我的问题是:

如何检测在 IIS 中运行的 ASP.net (MVC 4) 应用程序的 https 请求中使用的协议和密码?

我知道有一些方法可以将 SCHANNEL 请求记录到事件日志中,然后再次读出它们,但这对我来说听起来很丑陋。

我已经看到 System.Net.Security.SslStream 具有我需要的属性,例如:CipherAlgorithm、HashAlgorithm、KeyExchangeAlgorithm 和 SslProtocol,但我'不确定我可以在 mvc4 应用程序的控制器操作中从哪里获得这些属性。

【问题讨论】:

【参考方案1】:

ILSpy 确定的坏消息是,无法从 ASP.NET 内部的任何位置访问 System.Net.SslStream 实例。该类用于对网络进行直接编程,例如 WCF 框架。从 ASP.NET(无论是在 IIS 或 HttpListener 之上使用 System.Web 还是 OWIN),您可以做的最好的事情是获取一个服务器变量 (see list of IIS server variables),以确定连接是否受到与客户端协商的任何安全传输的保护.

就在网络请求期间确定性地从事件日志中读取数据而言……这似乎很可怕。但如果你能让它工作,请分享代码。 :)

或者,您可以尝试实现自己的 Owin 主机(又名 Web 服务器!),它在下面使用 SslStream。可能是。 :P 有关SslStream 编程的详细介绍,请参阅this article。

但是由于您已经能够关闭服务器上的某些协议(如this article,我假设)...您可以在两个不同的子域上设置您的站点,例如www.example.comsecure.example.com,其中前者是普通 Web 服务器,后者配置为仅接受 TLS 1.2 连接。然后,您将编写一些从 www.example.com 获取的引导逻辑,并尝试向 secure.example.com/securityUpgradeCheck 发出 AJAX 请求(可能带有样式精美的微调器动画和“请稍候,尝试保护此连接”文本以打动您的用户:))。如果该请求成功,则可以将用户重定向到 secure.example.com(可能是永久的,因为该用户代理然后已知支持 TLS 1.2,除非用户出于某种原因更改其浏览器设置)。

为了增加影响,请为安全域订购 EV SSL 证书,这样您的用户就会注意到安全性的升级。 :)

更新:在编写自定义(本机)ISAPI 过滤器(或扩展)以通过 SChannel API 获取此信息的理论基础上,我进行了更多挖掘。起初我很有希望,因为我发现了一个函数HSE_REQ_GET_SSPI_INFO,它会返回一个SSPI CtxtHandle 结构,您可以通过EXTENSION_CONTROL_BLOCK ServerSupportFunction 函数从自定义ISAPI 扩展中调用它。事实证明,CtxtHandle 结构代表一个 SChannel 上下文,可以为您提供对 SECPKG_ATTR_CONNECTION_INFO 属性的引用,您可以使用该属性检索 SSL 连接级别信息(与.NET 中的SslStream 类,据我所知)。然而,遗憾的是,Microsoft anticipated that possibility 并决定只有在您使用客户端证书时才能获得此信息。这种行为是“设计使然”。

有一个(本机)SSPI 函数QueryContextAttributes (Schannel),是我在长期通过 MSDN 搜索时发现的,可能工作。我还没有尝试过,它可能会因为与上面链接的 ISAPI API 限制相同的“设计”原因而失败。但是,它可能值得一试。如果你想探索这条路线,这里是an example of an ISAPI extension。实际上,通过这种方法,您或许可以使用更新的 IIS 7.0+ SDK 来编写 IIS 模块。

但是,假设您没有要求客户证书的奢侈,而且这种远景行不通,那绝对只剩下两个选择。

    使用不同的 Web 服务器(Apache 等),在同一物理/虚拟机上运行但在不同的端口等上(根据我们在 cmets 中的讨论,因为您无法启动另一台机器) .如果您只想向客户端提供信息性消息,那么这种方法再加上 AJAX 请求可能就足够了。是的,一个不同的端口很可能会被某处的防火墙阻止,但是嘿 - 无论如何这只是一个可选的信息消息。 依靠系统事件日志的半脆弱方法。 Enable Schannel event logging 然后编写一些事件日志查询代码来尝试将请求与最后记录的 Schannel 事件相关联。请注意,您需要找到一种方法来可靠地将事件日志中的任何内容与当前 HTTP 请求相关联,因此您可能还需要在此编写 ISAPI 过滤器/扩展或 IIS 模块找到 Schannel 上下文句柄的案例(这是我假设相关性所基于的)。

顺便问一下 - 您的负载平衡器是否配置为进行任何 SSL 拦截?因为无论如何这整件事都没有实际意义……只是一个需要考虑的想法。

更新:启用 Schannel 日志记录了这个 gem:

<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
    <Provider Name="Schannel" Guid="1F678132-5938-4686-9FDC-C8FF68F15C85" /> 
    <EventID>36880</EventID> 
    <Version>0</Version> 
    <Level>4</Level> 
    <Task>0</Task> 
    <Opcode>0</Opcode> 
    <Keywords>0x8000000000000000</Keywords> 
    <TimeCreated SystemTime="2014-08-13T02:59:35.431187600Z" /> 
    <EventRecordID>25943</EventRecordID> 
    <Correlation /> 
    <Execution ProcessID="928" ThreadID="12912" /> 
    <Channel>System</Channel> 
    <Computer>**********</Computer> 
    <Security UserID="S-1-5-18" /> 
  </System>
  <UserData>
    <EventXML xmlns:auto-ns3="http://schemas.microsoft.com/win/2004/08/events" xmlns="LSA_NS">
      <Type>client</Type> 
      <Protocol>TLS 1.2</Protocol> 
      <CipherSuite>0x3c</CipherSuite> 
      <ExchangeStrength>2048</ExchangeStrength> 
    </EventXML>
  </UserData>
</Event>

这可以直接从托管代码中读取。不幸的是,我认为 UserID 只对应于 IIS 工作进程 SID,但假设您可以提出某种相关启发式方法,您可以设置一个后台线程来不断轮询事件日志并为您提供最近建立的客户端列表握手(可能使用ConcurrentDictionary)。

那里。而已。不再好奇地调查我。我受够了。 :P

【讨论】:

感谢您的回答。我正在使用 Nartac 的 IIS Crypto 工具来禁用密码等,但这会导致与您的链接中描述的注册表项相同。您对安全站点的 ajax 请求的想法还不错,但这意味着我需要 1 个额外的服务器来探测是否启用了 TLS 1.2,我想这有点矫枉过正。出于合规性和其他原因,我也无法构建自己的 Web 服务器。我会研究更多选项,如果出现问题,请告诉您。干杯! 我实际上在想你可以把它做成一个虚拟机,甚至可能托管在你现有的服务器上。另一方面,如果您已经拥有多个 Web 服务器,则可以通过客户端的 TLS 版本进行一种负载平衡。这会更实用一些,因为所有服务器仍在忙于处理请求。但祝你好运!我能想到的唯一其他选择是使用具有可检查安全传输层的不同 Web 服务器(Apache?等?)。 我们已经有一个合适的负载均衡器和一个相当不错的网站背后的基础设施。向客户端提供应用程序的不仅仅是一台服务器。我可能会添加一个特定的 apache 网络服务器来运行所有这些验证并向页面返回一个小 json,然后我可以使用它来显示消息。但我现在已经知道,我们的 IT 部门不会太乐意维护 apache 网络服务器,并且通过合规性检查对其进行检查只是一场噩梦……我希望可以通过标准的 IIS 安装来完成。 现在有一个想法 - 您可以在负载均衡器中配置一条规则,以根据协商的 TLS 版本将不同的客户端引导到子场吗?诚然,远射。 在研究和实验的纯粹水平上+1!【参考方案2】:

感兴趣地阅读本文,因为我们遇到了完全相同的问题。

我突然想到,必须有一个公共 Web 服务可以查询此类信息,我做了一些研究,发现: https://www.howsmyssl.com/s/api.html

API 是here

此 API 可以从客户端 javascript 调用,它返回标准 JSON,可以轻松解析并向您的用户显示合适的警报。

您还可以将信息发送到您自己的 Web 服务以进行日志记录,并尝试将这些信息与您现有的 IIS 日志结合起来。

您面临的唯一问题是依赖第三方。这可以通过建立您自己的服务器并托管 code which is freely available on GitHub 来缓解。

我们将致力于这个解决方案,所以一旦我有了一些代码,我会更新这个答案。

再次感谢 Lars 提供上述全面的答案。我会将此作为评论添加到该帖子中,但是我认为值得创建一个单独的答案,以便人们可以更轻松地找到它。

【讨论】:

太棒了,谢谢,我一年前就可以使用它了 :-) 您最终实施了 James 什么解决方案? 技术含量不高的...我们通过电子邮件通知了所有客户有关更改的信息,他们可以在 SSL Labs 网站上检查他们的浏览器以及他们必须做什么才能获得最新信息: ssllabs.com/ssltest/viewMyClient.html @CarlR 查看我最近的答案,链接到***.com/questions/53461635/… 以获得文档化解决方案。 嘿@CarlR 你有机会编写代码来检测客户端浏览器的 TLS 版本吗?【参考方案3】:

How do you check the Negotiated TLS Handshake from the Server? 可以在 IIS 8.5 及更高版本的 ASP.Net MVC / WebAPI 下获得此功能。当我昨天回答时,至少它对我和其他几个人有用。

【讨论】:

以上是关于检查 asp.net mvc 4 应用程序中的 ssl 协议、密码和其他属性的主要内容,如果未能解决你的问题,请参考以下文章

使用 ASP.NET MVC 4 的不同项目中的区域

为啥我的 ASP.NET MVC 站点中的此 AJAX 请求会触发预检检查?

ASP.NET MVC 4 一键为每个订单提交 2 个表单

ASP.NET MVC

带有通用提供程序的 ASP.NET MVC 4 中的错误

IIS 7.5 中的 Asp.net mvc 4 应用程序问题