30

Is there a method for JavaScript running in a browser to determine which CA certificate is being used to authenticate the remote host for the browser's current HTTPS connection, and also obtain properties of that certificate, such as the name of the CA?

If not, are there any other options for programatically obtaining this information, such as ActiveX, Java, CGI on the server side, ...?

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
sutch
  • 1,225
  • 1
  • 13
  • 28

6 Answers6

19

You can use the opensource Forge project to do this. It implements SSL/TLS in JavaScript. You can make an ajax call to the server and use a callback to inspect the certificate. Keep in mind that the server is the one sending the JavaScript so this shouldn't be used to determine whether or not you trust the server the JavaScript is from. The Forge project does allow cross-domain requests, so if you are using this for trust, you can load the Forge JavaScript from a server you already trust and then contact the server you don't yet trust. However, unless that other server provides a cross-domain policy, you will not be able to perform the cross-domain request.

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

The blog links in the README provide more information on how Forge can be used and how it works.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
dlongley
  • 2,078
  • 14
  • 17
  • 5
    It looks like Forge can use either (not both at once) of the following approaches: 1. Use Flash for raw sockets. 2. Use TLS over WebSockets (this is not standard HTTPS, but requires custom server support). This may work for some people, but it's important to know what's going on. See https://github.com/digitalbazaar/forge/issues/97#issuecomment-33161672 – Matthew Flaschen Nov 04 '14 at 00:32
  • 6
    I don't think the answer is correct - at best, it's misleading. It seems that there is no way how to get the certificate info on the client side. Sure, Forge is interesting project, but this is more an interesting fact than the actual answer. – Tomas Kulich Mar 08 '17 at 20:07
10

Copying my own answer from Is there any way to access certificate information from a Chrome Extension

2018 answer: yes, in Firefox 62

You'll need to make a WebExtension, which is also called a browser extension.

See accessing security information on MDN

You can also check out the docs for:

You'll need Firefox 62.

Here's a working 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>"
    ]
}

enter image description here

It also may be implemented in Chromium once this code is merged.

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
  • According to cnst's answer, the capability in Mozilla already existed at least in 2014. Although either way it doesn't answer the question per se since you'd have to install an extension and not a standard website app. – Alexis Wilke Aug 07 '18 at 22:37
  • @AlexisWilke cnst's answer is for a deprecated API that has been removed. The question says "JS running in a browser" which this is, and also asks about alternate methods (which surely includes extensions even if you don't consider them to be "JS running in a browser"). – mikemaccana Aug 08 '18 at 11:55
4

JavaScript running in the web browser does not have access to the certificate information. The certificate information is also not passed through HTTP to the application. My research indicates that there is no way for the web application to determine if a man-in-the-middle attack has injected a bogus certificate somewhere between the host and client.

sutch
  • 1,225
  • 1
  • 13
  • 28
  • 3
    If the man-in-the-middle is impersonating your server to the client, they're certainly capable of replacing your javascript with something hard-coded with the "right" answers for your certificate... – Damien_The_Unbeliever May 04 '10 at 14:24
  • @curiousguy My understanding: Application data is sent between the web application and the the client browser over the application layer using HTTP. The certificate information is sent between the web server and the client browser over the transport layer using TLS. – sutch Jul 14 '18 at 13:31
  • I see, the *Web* application on the *Web* page, the JS code. (I thought standalone application. Sorry.) – curiousguy Jul 15 '18 at 11:29
  • At the same time, you have buttons/menu options that open popup windows with that information, so I don't see why it couldn't be made available to your JS environment. Probably not useful to prevent a MITM attack, though. – Alexis Wilke Aug 07 '18 at 22:12
  • I can't believe that this fundamental function is not available. People should be up in arms about this failure. Considering the wide number of CAs that your browser trusts by default, not being able to progmatically verify each browser tab connection's cert is a travesty. – raw-bin hood Jan 09 '23 at 03:37
3

No. You could obviously do it with AJAX/ActiveX/Java/Flash/Silverlight and a custom server-side script, but I can't see why you would need this.


EDIT: The idea above is that you would make a network request (using one of the above technologies) to the server and ask what certificate was used for that network request. The server could then inspect its own configuration and answer the question.

If the browser is somehow trusting an invalid certificate and connecting to the wrong server (e.g. a MITM server), the server could lie. Once the browser's trust mechanism is compromised, I don't know how to avoid that.

As far as I know, there is no way (purely using client side APIs) to directly ask the browser what cert it's using "for the browser's current SSL connection". Even Forge doesn't do that. It creates an entirely parallel SSL session, but it doesn't let you ask about the browser's native SSL session.

Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
  • 2
    I'll bite... how would this be done in AJAX? The reason why this is needed is to check whether a client is using a bogus CA certificate, thereby allowing man-in-the-middle attacks. – sutch Mar 08 '10 at 18:51
  • 1
    @MaxRied, the answer is "No, but", and I said "No...". The question was about how to "determine which CA certificate is being used to authenticate the remote host for the browser's current SSL connection" I.E. given the browser has a normal SSL stack (currently in use), can you ask the browser about what certificate and such are being used for the current SSL connection. Basically, no you can not, no matter how much JS you write. (Forge creates a parallel SSL session, it doesn't inspect the standard one). However, you can ask your own server, subject to the standard issues of SSL trust. – Matthew Flaschen Nov 04 '14 at 00:46
  • It's more a "Hey, don't do that.". OP did not ask if you think this is a good idea (which would be off-topic as "primarily opinion based", which renders your answer off-topic, too, but that's another point...). He asked how to do this. This is no platform for questioning problems but for solving them. You should know that. – bot47 Nov 04 '14 at 10:44
  • 1
    @MaxRied, no, it's not. It's impossible to do what the actual question asked, which is why my answer starts "No." The question asked, can you know client-side "which CA certificate is being used to authenticate the remote host for the browser's current SSL connection". I believe the answer is "no, that information is not available client-side, but...". None of the other answers explain how to do that either (the Forge one is about setting up a separate SSL stack, not inspecting the browser's SSL stack or certificates). – Matthew Flaschen Nov 05 '14 at 03:49
  • @MaxRied, also note it's [perfectly fine](https://meta.stackoverflow.com/q/261168/47773) to say something's impossible. The reason I didn't *only* say that is that I hope the extra context is useful and elaborates my point. – Matthew Flaschen Nov 05 '14 at 03:54
  • Hi @MatthewFlaschen, I've added working code to do this using the recently added APIs in Firefox 62 webextensions. If you're happy with that, please mark it as accepted! – mikemaccana Jun 22 '18 at 23:04
1

AFAIK not with Javascript alone. But some webservers allow you to access the connection parameters of the thread or process. A serverside script can then send those values along with the request and you use it.

I found this for nginx webserver: http://wiki.nginx.org/NginxHttpSslModule (Look at the bottom of the page for the variables). It should be possible to set them as environment variables and pass them to your FastCGI processes or whatever you use.

AOLServer/Naviserver allows similar access with the nsssl module.

initall
  • 2,385
  • 19
  • 27
  • Thanks for searching. The nginx webserver information applies to client certificates, which are used to authenticate the user with the web application. I'm interested in obtaining information about the CA certificate used on the client's browser--the CA certificate which authenticates the website that the browser is accessing. – sutch Mar 08 '10 at 16:15
-3

In practical terms, this has little use -- why would you need to know certificate information from JavaScript on the individual page already rendered?

  • If it's not trusted, then obviously your code could have been altered, too, so, it cannot be trusted, either.

  • If the certificate is actually trusted, then how would you be able to distinguish the scenario from the one where the certificate is not trusted, but your code has been modified through a MitM attack to think otherwise?

So, checking certificates would only be useful from within Browser Extensions (which are presumed to be trusted code) as opposed to the scripts in the individual pages themselves. Such interface that extensions use is browser-specific, and not all browsers even provide it. For example, whereas Mozilla browsers do let you peek into the certificates (affording extensions like the EFF SSL Observatory), Chromium is still lacking.

Community
  • 1
  • 1
cnst
  • 25,870
  • 6
  • 90
  • 122
  • 6
    Here is one scenario: A proxy exists at a company which is used to capture all traffic. The proxy intercepts TLS traffic using a self-signed certificate. The self-signed certificate is installed on each of the company's computers. Browsers would not report any problem. The company may only be capturing traffic and likely does not have the resources to rewrite the JavaScript performing MitM detection when being returned by multiple websites. – sutch Feb 04 '14 at 16:47
  • 1
    @MaxRied, giving a -1 just because there is no solution, and the answer specifically states so (and explains why that's the case) is not really fair, especially when all the other answers are basically a "no" anyways. – cnst Nov 06 '14 at 20:27
  • 2
    " In practical terms, this has little use -- why would you need to know certificate information from JavaScript on the individual page already rendered?": This is not a "No", that's a "No, and your question is wrong! Why could someone ever ask something absurd like that?!". – bot47 Nov 06 '14 at 20:33
  • @MaxRied, understanding the question means already being half-way to the answer. There are lots of absurdities in the software engineering world; giving a -1 for a frank answer that dots the i's and crosses the t's is not really fair. – cnst Nov 06 '14 at 20:42
  • 1
    It's defense in depth. – curiousguy Jun 08 '18 at 02:03
  • "_"No, and your question is wrong! Why could someone ever ask something absurd like that?!"_" And indeed many questions on SO are just stupid and deserve a "your question is stupid" answer. (But that question isn't.) – curiousguy Jul 14 '18 at 13:41