在网络浏览器中,JavaScript是否可以获取有关当前页面使用的HTTPS证书的信息?

31

在浏览器中运行的JavaScript是否有一种方法可以确定用于验证当前HTTPS连接的远程主机的CA证书,并获取该证书的属性,例如CA名称?

如果没有,是否有其他选项可以以编程方式获取此信息,例如ActiveX、Java或服务器端CGI等?

6个回答

19
您可以使用开源项目Forge来实现此功能。它在JavaScript中实现了SSL/TLS。您可以向服务器发起ajax调用并使用回调来检查证书。请记住,服务器是发送JavaScript的一方,因此这不能用于确定您是否信任提供JavaScript的服务器。 Forge项目确实允许跨域请求,因此如果您要使用此功能进行信任,请从已经信任的服务器加载Forge JavaScript,然后联系尚未信任的服务器。但是,除非其他服务器提供跨域策略,否则您将无法执行跨域请求。

https://github.com/digitalbazaar/forge/blob/master/README.md

README中的博客链接提供了有关如何使用Forge以及其工作原理的更多信息。


5
看起来 Forge 可以使用以下两种方式之一(但不能同时使用):
  1. 使用 Flash 进行原始套接字传输。
  2. 使用 TLS over WebSockets (这不是标准的 HTTPS,需要自定义服务器支持)。
这对某些人可能有效,但了解其中的情况是很重要的。请参阅 https://github.com/digitalbazaar/forge/issues/97#issuecomment-33161672。
- Matthew Flaschen
6
我认为答案不正确,最多也只是误导性的。似乎没有办法在客户端获取证书信息。当然,Forge 是一个有趣的项目,但这更像是一个有趣的事实,而不是真正的答案。 - Tomas Kulich

10

Is there any way to access certificate information from a Chrome Extension中复制我的答案。

2018年的答案:是的,在Firefox 62中可以

你需要创建一个WebExtension,也称为浏览器扩展程序。

请参阅MDN上的访问安全信息

您还可以查看以下文档:

您需要Firefox 62。

这是一个有效的background.js

var log = console.log.bind(console)

log(`\n\nTLS browser extension loaded`)

// https://developer.chrome.com/extensions/match_patterns
var ALL_SITES = { urls: ['<all_urls>'] }

// Mozilla doesn't use tlsInfo in extraInfoSpec 
var extraInfoSpec = ['blocking']; 

// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest/onHeadersReceived
browser.webRequest.onHeadersReceived.addListener(async function(details){
    log(`\n\nGot a request for ${details.url} with ID ${details.requestId}`)

    // Yeah this is a String, even though the content is a Number
    var requestId = details.requestId

    var securityInfo = await browser.webRequest.getSecurityInfo(requestId, {
        certificateChain: true,
        rawDER: false
    });

    log(`securityInfo: ${JSON.stringify(securityInfo, null, 2)}`)

}, ALL_SITES, extraInfoSpec) 

log('Added listener')

manifest.json:

{
    "manifest_version": 2,
    "name": "Test extension",
    "version": "1.0",
    "description": "Test extension.",
    "icons": {
        "48": "icons/border-48.png"
    },
    "background": {
        "scripts": ["background.js"]
    },
    "permissions": [
        "webRequest",
        "webRequestBlocking",
        "<all_urls>"
    ]
}

在此输入图片描述

一旦这段代码被合并,它也可以在Chromium中实现。


根据cnst的回答,Mozilla中的这种功能至少在2014年就已经存在了。虽然无论如何,它并不能直接回答问题,因为你需要安装一个扩展而不是标准的网站应用程序。 - Alexis Wilke
@AlexisWilke 的回答是针对已被删除的API的。问题中提到了“在浏览器中运行的JS”,这也是事实,并且还询问了替代方法(即使您不认为它们是“在浏览器中运行的JS”,但肯定包括扩展)。 - mikemaccana

4

运行在Web浏览器中的JavaScript无法访问证书信息。该证书信息也不通过HTTP传递给应用程序。我的研究表明,Web应用程序无法确定是否存在中间人攻击,即恶意证书被注入到主机和客户端之间。


3
如果中间人正在模拟您的服务器向客户端发送信息,他们有能力将您的 JavaScript 替换为一些硬编码的代码,可以为您的证书提供“正确”的答案。 - Damien_The_Unbeliever
@curiousguy 我的理解:应用程序数据通过HTTP在应用层和客户端浏览器之间发送。证书信息通过TLS在Web服务器和客户端浏览器之间的传输层发送。 - sutch
我明白了,在Web页面上有一个Web应用程序,还有JS代码。(我以为是独立的应用程序。抱歉。) - curiousguy
同时,您可以使用按钮/菜单选项打开带有该信息的弹出窗口,因此我不明白为什么它不能在您的JS环境中提供。虽然可能无法防止MITM攻击,但可能并不实用。 - Alexis Wilke
我简直不敢相信这个基本功能居然没有提供。人们应该对这种失败感到愤怒。考虑到您的浏览器默认信任的众多CA,无法编程验证每个浏览器选项卡连接的证书是一种悲剧。 - raw-bin hood

3
不行。显然,您可以使用AJAX/ActiveX/Java/Flash/Silverlight和自定义服务器端脚本来完成此操作,但我无法看出为什么您需要这样做。
编辑:上面的想法是,您将通过网络请求(使用上述技术之一)向服务器询问用于该网络请求的证书。然后,服务器可以检查其自己的配置并回答问题。
如果浏览器以某种方式信任无效证书并连接到错误的服务器(例如MITM服务器),则服务器可能会撒谎。一旦浏览器的信任机制被破坏,我不知道如何避免这种情况。
据我所知,没有办法(仅使用客户端API)直接询问浏览器正在使用哪个证书“用于浏览器当前的SSL连接”。即使Forge也不这样做。它创建了一个完全平行的SSL会话,但它不允许您询问浏览器的本机SSL会话。

2
我来说一下...这个怎么用 AJAX 实现?需要这样做的原因是为了检查客户端是否使用虚假的 CA 证书,从而防止中间人攻击。 - sutch
1
@MaxRied,答案是“不行,但是”,我说“不行……”。问题是关于如何“确定用于验证浏览器当前 SSL 连接的远程主机的 CA 证书是哪一个”。即:假设浏览器有一个正常的 SSL 堆栈(目前正在使用),你能否询问浏览器当前 SSL 连接所使用的证书等信息。基本上,无论你编写多少 JS,都不行(Forge 创建一个并行 SSL 会话,而不检查标准会话)。但是,可以向您自己的服务器查询,前提是符合 SSL 信任的标准问题。 - Matthew Flaschen
这更像是一种“嘿,不要那样做”的态度。OP并没有问你是否认为这是一个好主意(这将被视为“基于主观看法”,这也使得你的回答不相关,但这是另一个问题...)。他问的是如何实现这个功能。这不是质疑问题的平台,而是解决问题的平台。你应该知道这一点。 - bot47
1
@MaxRied,不是这样的。实际问题所问的是不可能做到的,这就是为什么我的答案以“不”开头。问题是,你能否在客户端知道“用于验证浏览器当前SSL连接的远程主机的CA证书是哪个”。我认为答案是“不,客户端无法获得该信息,但是...”。其他答案也没有解释如何做到这一点(Forge的答案是关于设置单独的SSL堆栈,而不是检查浏览器的SSL堆栈或证书)。 - Matthew Flaschen
@MaxRied,还要注意完全没问题说某些事情是不可能的。我之所以没有仅仅这样说,是因为我希望额外的上下文有用并且能够阐述我的观点。 - Matthew Flaschen
嗨@MatthewFlaschen,我已经添加了可工作的代码,使用Firefox 62 webextensions中最近添加的API。如果您对此满意,请将其标记为已接受! - mikemaccana

1

据我所知,仅使用Javascript是不行的。但是一些Web服务器允许您访问线程或进程的连接参数。然后,服务器端脚本可以将这些值与请求一起发送,并且您可以使用它。

我在nginx Web服务器上找到了这个: http://wiki.nginx.org/NginxHttpSslModule (请查看页面底部的变量)。应该可以将它们设置为环境变量并将它们传递给您使用的FastCGI进程或其他内容。

AOLServer/Naviserver使用nsssl模块允许类似的访问。


感谢搜索。Nginx Web服务器信息适用于客户端证书,用于对Web应用程序进行身份验证的用户。我有兴趣获取有关客户端浏览器上使用的CA证书的信息--用于验证浏览器访问的网站的CA证书。 - sutch

-4

实际上,这没有什么用处——为什么你需要从已经呈现的单个页面中的JavaScript了解证书信息呢?

  • 如果它不被信任,那么显然你的代码也可能被修改,因此它也是不可信的。

  • 如果证书实际上是受信任的,那么你如何能够区分证书不被信任的情况和通过MitM攻击修改了你的代码以认为否则的情况?

因此,检查证书只有在浏览器扩展程序内部才有用(这些扩展程序被认为是可信代码),而不是在页面本身的脚本中。这种扩展程序使用的接口是特定于浏览器的,并且并非所有浏览器都提供它。例如,尽管Mozilla浏览器确实允许您窥视证书(为EFF SSL Observatory等扩展程序提供支持),但Chromium仍然缺乏该功能


6
以下是一种情况:某公司存在一个代理,用于捕获所有流量。该代理使用自签名证书拦截TLS流量。自签名证书已安装在公司的每台计算机上。浏览器不会报告任何问题。该公司可能只是捕获流量,很可能没有资源来重写由多个网站返回的执行MitM检测的JavaScript。 - sutch
1
@MaxRied,仅因为没有解决方案,并且答案明确说明了这一点(并解释了为什么会这样),就给出-1并不公平,特别是当所有其他答案基本上都是否定的时候。 - cnst
2
从实际应用角度来看,这没有什么用处——为什么你需要在已经呈现的个别页面上使用JavaScript了解证书信息呢?这不是“不可以”,而是“不可以,而且你的问题本身就是错的!为什么会有人问这样荒谬的问题呢?!” - bot47
@MaxRied,理解问题意味着已经走了一半的答案。在软件工程世界中有很多荒谬之处;对于一个点滴到位的坦率回答给予-1并不公平。 - cnst
1
这是深度防御。 - curiousguy
"不,而且你的问题也是错的!为什么有人会问这样荒谬的问题?!" 实际上,许多在SO上的问题都很愚蠢,值得回答“你的问题很愚蠢”。(但那个问题不是。) - curiousguy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接