25

I'd like to gather certain details of an SSL certificate on a particular web-site. I know this is straightforward using the openssl tool on Linux/MacOSX. However is the same or similar possible in JavaScript?

I understand that the browser handles socket connections and that the SSL handshake occurs prior to any party sending data. However in an XMLHTTPRequest, I'd like to know if its possible to get these details as some sort of response code etc?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
shaond
  • 544
  • 1
  • 6
  • 12
  • I don't think this is possible. – SLaks Apr 09 '10 at 00:41
  • I've been looking for a Javascript API to test the proven credentials of cross-site requests to improve site security. Sadly the browser is discarding this information, which is then forcing scripts to blindly trust that 3rd party content is trusted now because it was trusted in the past. That's a sad state of affairs. :-( – Wil Nov 25 '17 at 14:15
  • 1
    Some people add cert details to response headers. In that setup you could make an xhr request and read the req.getAllResponseHeaders() – Spikolynn Dec 02 '17 at 10:49
  • That's better than nothing, but doesn't provide any actual security. I'm mostly concerned with pulling data from advertisers. When I author monetizing ad code for a client, I don't want to have to come back and check that the advertiser is still in business every few months to prevent their site from being hijacked because I'm pulling script resources from a site no longer owned by the advertiser, and I don't want to tell the client "This is safe now, but you're on your own now that I'm done. Good luck!" – Wil Mar 20 '18 at 06:09

4 Answers4

14

This information simply isn't exposed to javascript, it is so rarely used (well never since it isn't available, but it would be rarely used) that it wasn't deemed important enough to add to the javascript object model I suppose...same for any very rarely used feature left out of anything.

Of course, it could have also been left out for security reasons...I'm not creative enough to come up with one at the moment, but I'm sure there's an exploit to be had there as well.

Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
  • 2
    @GregS - I can't think of one either...but I've said that 100 times before and someone will come up with a vulnerability I would *never* have consireded, different mindset I suppose...so I was just throwing that option out there. If you were hosting the javascript in question...wouldn't you be the one with the certificate already? That's what leads me to think there might be more some nefarious use *somehow* for this. As I said though, definitely not my area of expertise, I'll leave it to you and others who specialize in this area elaborate on what may be possible. – Nick Craver Apr 09 '10 at 01:17
  • Thanks Nick, I guess I'll have to think about how to grab SSL details on a client's end in a cross platform way, without JS or installing alternative binaries (such as openssl, curl/wget). – shaond Apr 09 '10 at 01:34
  • 2
    It would improve the security of my pages if I could use Javascript to test that a 3rd party site I am embedding content from is still the same entity that I trusted when I authored the page. Currently the browser goes to the effort of proving that information, then discards it, forcing my pages to assume that a trust relationship still exists today because there was one in the past. I almost -1'd your post for spouting blind FUD. There's no exploits to be had from knowing who you are talking to. Please rethink your answer. – Wil Nov 25 '17 at 14:20
  • 1
    @JamesKPolk in fact it is a security problem, as websites can't detect if SSL has been broken and a fake cert being used. – aaa90210 Oct 11 '18 at 21:37
  • @aaa90210: It's nice that you have replied 8.5 years later, but certificates are public values and are not hard to get by any of a myriad of means. The fact that the javascript engine of a browser cannot easily do so is not a security problem. – President James K. Polk Oct 11 '18 at 22:26
  • @JamesKPolk yes but if you can't check the current webpage's cert against the cert you think it *should* be you have a problem. – aaa90210 Oct 11 '18 at 23:59
  • @aaa90210: Incorrect. That is what the browser does, not your javascript. – President James K. Polk Oct 12 '18 at 01:12
6

The certificate isn't part of the DOM, so no, this won't be possible. Sorry!

John Feminella
  • 303,634
  • 46
  • 339
  • 357
  • 4
    Yes, sad but true. So we need some concerned stakeholders to actually make some noise about this to W3C, Mozilla, Chromium, (and Safari and Edge will follow suit once there's CVE's against their platforms for failing to follow.) – Wil Mar 30 '18 at 10:19
2

The current JS language standard does not expose certificate information; beyond that It probably depends on how you're using JavaScript, if you're expecting the end user's Browser to expose certificate information then it's going to be really problematic because you'd need to get at the minimum FF, Chrome, Safari, IE, Edge, ... to expose it.

However, as mentioned on this Information Security post, this is not really a desirable option for these browsers to implement, as it would allow a situation where a website developer could write code to mistakenly trust user side credentials.

It's not so much a visibility security risk that prevents javascript from accessing the browser's current SSL Certificate info, but more of a fourth wall barrier security risk where the JS developer must be aware that the "user-accepted" certificate is not necessarily the one that the website provided. The HTML page really shouldn't be handling the security issues with client side code, but instead it should be able to depend on the security layer to do it's job properly. (I can totally understand wanting to checkup on the security layer, but any managerial work you do at the top layer is just going to be either superficial or a reworking of the entire biosphere)

Because let's assume for a moment that javascript did provide a way to work with the certificate, then when Bob already trusts Mallory because his security is broken there is no way of stopping the following exchange:

Office Worker Bob is on one side of the great firewall of Mega Corp., IT Mallory is in charge of the firewall passing traffic in and out of the company locally, and Web Host Alice's awesome website is out on the WWW.

  1. By Mega Corp. company policy Bob is setup to just accept what Mallory has to say at face value.
  2. Bob who would like to visit Alice's site, but has no direct outside access, tries to establish a secure connection through the firewall by holding up his certificate(Eg:"I hereby declare I am Bob") and asks Alice in a really convoluted way, "what certificate did I send to you?"
  3. Mallory gets Bob's request, but instead passes on her own(Eg:"Uh, Bob says it's ok for me to read his webmail"), and even though Mallory doesn't understand Bob's convoluted question she still repeats it to Alice, "akdvyfenwythnwerhy?".
  4. Alice does some math and figures out that "akdvyfenwythnwerhy?" is asking "what certificate did I send you?" and answers back to Mallory with what she sees("Hi Bob this is Alice you said: Uh, Bob says it's ok for me to read his webmail").
  5. Mallory does some math, has an ah ha moment "akdvyfenwythnwerhy?=what certificate did I send to you?", and answers Bob's question on behalf of Alice("Hi Bob this is Alice(Mallory) you said: I hereby declare I am Bob").
  6. Bob believes life is good and continues on to read his webmail, because by company policy he knows Mallory would never lie to him.
  7. Mallory now able to read both sides of the conversation passes on Bob's request to read his webmail to Alice.
  8. Alice gets Bob's request and says hey wait a minute Bob I need you to run this JS code to prove you know you're talking to Alice.
  9. Mallory gets the code, runs it, and sends the results stating that she knows she's talking to Alice back to Alice.
  10. Alice says, good enough for me here's your webmail.
  11. Mallory reads Bob's webmail before passing it on to Bob, and everyone is blissfully happy.

(Note: I did not address the case where you're running JS server-side, then it would depend on what program you're using to run your JS code.)


Edit 4/4/2018 -- While the above is not wrong it's more from the perspective of embedded and linked JS than it is about the `XMLHTTPRequest` JS object; moreover quite possibly the strongest argument to be made against sharing PKI details with `XMLHTTPRequest` is as follows:

There needs to remain a strong dividing line between the HTTP portion and the S portion of the HTTPS protocol. JavaScript and it's XMLHTTPRequest object reside on the HTTP(app layer) side of that line, while the whole certificate exchange process resides on the S(trans/sec layer) side of that line. In order to keep the security side atomic(hot-swappable) its internal workings cannot be exposed across the line to the application side; because there may come a day when the transport/security layer no longer uses PKI certificates to facilitate its secure communication service, and when that day comes no one would need to rewrite any existing JS code that was relying on details contained within those certificates to deal with the propagation wave caused by the www community slowly adopting their favorite flavor of any new security layer.

That being said, the security side does appear to also be doing legal entity vetting --at least in some cases like EV certificates--, and it is IMO a short coming of RFC7230 section 2.7.2 that it does not redefine the authority of the https-URI to include an optional legalentity that the security layer would use when verifying the url it is communicating with is not only the proper end point but also currently under control of the intended business relation.

authority     = [ userinfo "@" ] host [ "#" legalentity ] [ ":" port ]
legalentity   = *( unreserved / pct-encoded / sub-delims )
Community
  • 1
  • 1
Gregor y
  • 1,762
  • 15
  • 22
  • 1
    Your answer doesn't address the question. The question was whether Javascript could access the data in the Certificate which has already been proven by the browser's transportation layer. Unfortunately the browser discards it. Nothing in his question implied implementing the transport in Javascript, or bypassing the transport security. -1 – Wil Nov 25 '17 at 14:28
  • @Wil, in looking at your comments spread out across the thread I believe you're trying to use JS when you should be looking at a PHP or ASP solution. JS is client side and if your trying to check certificate info on a user's machine that's a little too late in the game. – Gregor y Dec 08 '17 at 17:36
  • I think you're discounting the fact that real applications are being written to run in the browser - applications that should be able to do a simple thing like prove that they are talking to the peer they intended to talk to. PHP doesn't run in the browser. ASP doesn't run in the browser. The future is not server-side applications. Preventing an application from proving the identity of a peer reduces the security of the transport from SSL-EV to SSL-broken cert. – Wil Mar 20 '18 at 06:14
  • @Wil, writing the "proving" function in JS and then handing that function over to a hacker and asking them nicely to be sure and use its code unmolested for validation is a bit optimistic. – Gregor y Mar 21 '18 at 03:11
  • Moreover, preventing the client JS app from believing its self-justified proof of validity on a compromised token stops it from making a very big mistake; the JS app layer gets its data including the app's own code from the security layer below, so when the security token is compromised it is fairly safe to assume likewise for the JS code as well and there is no magical proof of validity which when swapped out with `function check_valid(){return true;}` by an intermediary party is not going to always just rubber-stamp the broken token as shown in the overly simplified real-world example above. – Gregor y Mar 21 '18 at 05:37
  • When I authored the code I had a trust relationship with the organization "Example.Com Ltd". I'd like to verify the Organization that responded has not changed, ie. response.certificate.peer.o=="Example.Com Ltd". Whether my script was loaded in a secure context is a red herring. The browser itself could be loaded in an insecure context. Nobody (other than you) suggested that SSL/TLS proofs be conducted in Javascript, and I've already disabused you of that ridiculous notion. The browser itself already verified the DOMAIN and THE PEER. I want to verify the PEER. – Wil Mar 21 '18 at 19:56
  • @Wil, It only feels like a red haring because your specific case use is way off topic. The security layer has two responsibilities first to make sure no one is listening-in and/or changing things around, and second to make sure the client is not talking to an imposter. – Gregor y Mar 22 '18 at 16:32
  • In your case `response.certificate.peer.o=="Example.Com Ltd"` would not work because: `response.certificate.peer.o` would be for the current document and should have `MyOwnSite.com LLC`, an intermediary could swap `if(response.certificate.peer.o=="Example.Com Ltd"){DoCode();}` with `if(true){DoCode();}`, likewise an intermediary could just author their own certificate with the o field set to the value the code is looking for ie `"Example.Com Ltd"`... – Gregor y Mar 22 '18 at 16:32
  • I believe what you really want to do in your situation is to use PHP/ASP to forward the 3rd party JS application. Your JS app would use AJAX to request and load the 3rd party code from a PHP/ASP form on your domain. The PHP form then: requests the code from the 3rd party, does the validation, if the validation passes, save a copy on your server and forward it on to the client, but if the validation fails then the PHP form can pass on the last good copy of the 3rd party code to your app running client side. – Gregor y Mar 22 '18 at 16:32
  • This would rely on the security layer to take any intermediary between your domain and the client out of the picture, and by manually storing the 3rd party's credentials on your domain would rely on your PHP to take any intermediary between your domain and the 3rd party's out of the picture as well (which if properly coded would be mathematically provable). – Gregor y Mar 22 '18 at 16:33
  • As for your suggestion of why it wouldn't work, that is just an example of your ignorance of XHR and Javascript programming, Every XHR is a response object, and I would be testing the response object from the 3rd party peer. You've now proven that your answer is off-topic because you don't even understand the topic. – Wil Mar 30 '18 at 10:11
  • Thankyou for recognising a need to verify the peer. Now recognise that having to call back to my app's server is a hack and doesn't solve the problem. If the client is loaded on a server with a compromised DNS server and it is being directed to an entirely different host than my app's server, then my app's server results are pointless. There's zero reason to hide the browser-verified certificate details of the request to Javascript via the request object. Other than the paranoid rantings of a few people who have no clue what they're talking about. – Wil Mar 30 '18 at 10:15
  • And while I'm at it the whole "4th wall" argument is FUD. Currently apps are forced to trust that the user did NOT accept an invalid cert from the 3rd party site. Letting the script verify peer-identifying parts of the cert, as a 2nd line of defense, does nothing whatsoever to reduce the security of the app or the user. It does let the app refuse to operate if the user does something stupid, or if there's a MITM or Spoof with a successfully forged cert (there's been tens of thousands of these in the last couple years.) Your example also demonstrates your misunderstanding of how PKI works. – Wil Mar 30 '18 at 10:33
  • 1) This has nothing to do with DNS, but valid https would take care of the redirect problem, 2) I'm sorry you fail to see the hole in your security model, but PKI works because there is a trusted certificate store on the clients' computer. When that store is not breached, then a 2nd layer is superfluous; and when it is breached you cannot pass script code across that breach to patch it. Because that would entail re-implementing a new layer of the certificate store within a compromised environment. – Gregor y Apr 03 '18 at 02:08
  • 3) Superfluous or not, against just about every recommendation I've seen, people like yourself are still doing XSS; so there should probably be a mechanism built into XHR to for the host to 'approve' and/or delegate the 'approval' of the 3rd party resources. Which it looks like there may be some progress on https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS – Gregor y Apr 03 '18 at 02:08
  • The problem being CORS only allows the library host to approve the usage of its resources by the franchise host, it is still missing the bit where the franchise approves the code checked out by the client from the library prior to the client running it. Until that gets implemented you're stuck with your host checking out the code approving it and relaying on to the client. Where how you checkout and approve it is up to how you wish implement it server-side, but at least then the JS dev team hasn't exposed the rest of us to the false hope of verifying faulty credentials using compromised code. – Gregor y Apr 03 '18 at 03:59
  • Also, as a side note you're going to want to fix your validator script to walk back up the certificate chain until it gets to the EV certificate before it relies on the legal entity presented by `.certificate.peer.o`, as that's the only one which has gone through the vetting process. – Gregor y Apr 03 '18 at 15:57
  • 1) the client can accept a bad MITM cert when DNS is hijacked. Firefox and Chrome for example offer this to the client user. At that point yes all bets are off, but at least we can make it harder for the MITM to succeed by rejecting data that isn't forged well. Some effort is better than no effort. – Wil May 10 '18 at 09:17
  • 3) Yes, it's XSS. Just about all 3rd party ad apps use XSS, which is inherently insecure because we're handing off control of the browser scripting engine to a 3rd party that we trusted IN THE PAST but have no idea whether we should still trust them now. Hence the need to ensure that they are still the entity that we trusted when the code was written. Testing server-side has the potential, I agree, but it won't deal with the MITM and it requires extra requests, which elevates the service cost. Doing it client side would cost literally nothing and be more effective. – Wil May 10 '18 at 09:20
  • CORS is off-topic. It has nothing to do with this whatsoever. It's a relaxation of XSS security constraints, not a proof of peer identity. If CORS let you specify that XYZ.COM was a valid 3rd party script source only when its EV organization is also "same trusted organization", then yes, it would meet the requirements. But that isn't part of the spec. CORS does let you use O_AUTH, cookies, etc to validate the 3rd party. Again that implies more overhead, this time requiring dynamic content from what would otherwise be a static CDN. – Wil May 10 '18 at 09:38
  • Again I'd like to reiterate that this isn't about distrusting the security of the transport layer, though it isn't entirely trustworthy as previously mentioned. It's about enforcing an organizational relationship requirement that PKI does enforce, and which the browser presents to the client user via the green bar. However the script layer then proceeds as the user's agent on their behalf under the guise of the trust relationship demonstrated by that green bar, meanwhile the browser prevents the script layer from behaving in a trustworthy manner - by preventing required trust proofs. – Wil May 10 '18 at 09:52
  • Your assertion that the script must blindly trust the transport layer based on Cert validity equates to Bob blindly trusting that he has Sharon's phone number because he's spoken to her at that number once in the past. Then Sharon is replaced with Shirley who doesn't have access rights, Bob calls and blindly discloses vitally secure data to Shirley, because he doesn't perform a simple "Hello, is this Sharon?" handshake after dialling. But I appreciate that you have edited your text to reflect your growing understanding of these concerns. Hope now you understand even more. – Wil May 10 '18 at 10:04
  • that's why I suggested that adding "Sharon" to the URL or in your case phone number would allow the security layer to green bar the user or 'page contains non-secure content' the JS with the option to reject the call when the phone company reassigns the phone number to Shirley. However it still leaves you in a lurch since that wouldn't really let the JS stop the unknown adware from going through if the user blanket ok'd it; at that point `XMLHTTPRequest` would still need to expose a security validation status back to the JS layer. possibly: `{NON_SECURE, VALID_ENDPONT, VALID_EV}` – Gregor y May 11 '18 at 16:08
  • although with a targeted set of certificates, adding the security status may cause `XMLHTTPRequest` to leak who's in the end user's circle of trust. because then a malicious site controller could write JS to have `XMLHTTPRequest` ping `https://badguy.com/mixed-content-of-targeted-certificates?cert1_accepted=yes&cert2_accepted=no&cert3_accepted=yes` – Gregor y May 11 '18 at 16:45
  • Much ado over nothing post. OP is asking how to get >>server cert<<, nothing to do with trusting the client. If you're going to say "no, just blindly trust the browser and not let clients be able to verify server signature on some data msgs", at least give a suitable reply. – theAnonymous Jul 27 '18 at 02:34
  • @user3635998 I'm saying JS has no better choice then to "blindly" trust the browser to do the security layer. Because JS is not a program that the user bought at a store brought home and installed on their PC, it was just a bit of text sent across that very same security layer. You can't trust it to scan itself after it arrives unless you already blindly trusted the browser security to deliver it safely; that's why for the same reason anti-virus software is compiled in a clean room. – Gregor y Aug 01 '18 at 03:34
  • Like i said, much ado over nothing. In the future, 1000000 years in the future may not use cert, blah blah blah herpity derp. There is no excuse not to let the JS have access to the server cert, as seen from the browser. Having a window.getCert() is bad, because the user didn't buy such a function. Just like the user didn't buy the browser. mmmmkay, right. pffft. – theAnonymous Aug 01 '18 at 04:32
  • BTW, should the site no longer use a cert, and the JS relies on having a cert, there'll be this magical thing called an error. – theAnonymous Aug 01 '18 at 04:37
  • @user3635998 yes [1000000 years](https://www.qiskit.org/) in the future your site still serves up some archaic text file with `window.getCert()` ... and then what? oh yeah the client's pc interprets it as "code" and runs `window.getCert=function(){return function(){return 'valid cert'}}();` because it was delivered "securely" to the browser. But hey, if you have any links on which cutting edge browsers implement getCert() because it's [such a novel idea](https://bugzilla.mozilla.org/show_bug.cgi?id=728650) that nobody has thought of before then please do share. – Gregor y Aug 02 '18 at 04:57
  • Sarcasm is lost on the ____. People like yourself are totally incapable of explaining why letting the JS know the server cert is a bad thing. – theAnonymous Aug 02 '18 at 05:07
1

Nope, not possible.

It is possible to detect via javascript whether the current page being viewed is over an SSL connection (document.location.protocol=="https:"), but that's about it.

Sean
  • 781
  • 1
  • 4
  • 14
  • and then you can pass that `document.location` value to a REST service to get the certificate information. – Saber Sep 11 '18 at 23:25
  • @Saber the "man in the middle" type of attack would still be a concern... I want to check the certificate public key signature, to make sure the browser talks directly to _my_ server. But yeah, interesting idea... worth exploring... – AlexV Jan 18 '19 at 22:05