Is there a way to get SSL certificate details using JavaScript?

27,002

Solution 1

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.

Solution 2

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

Solution 3

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.

Solution 4

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 )
Share:
27,002
shaond
Author by

shaond

Co-founder of NewsMaven Pty Ltd (newsmaven.co). A technology company that builds software solutions for the Publishing industry.

Updated on February 16, 2021

Comments

  • shaond
    shaond about 3 years

    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?

  • Nick Craver
    Nick Craver about 14 years
    @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.
  • shaond
    shaond about 14 years
    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).
  • Wil
    Wil over 6 years
    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
    Wil over 6 years
    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
  • Gregor y
    Gregor y over 6 years
    @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.
  • Wil
    Wil about 6 years
    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.
  • Gregor y
    Gregor y about 6 years
    @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
    Gregor y about 6 years
    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.
  • Wil
    Wil about 6 years
    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.
  • Gregor y
    Gregor y about 6 years
    @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
    Gregor y about 6 years
    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
    Gregor y about 6 years
    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
    Gregor y about 6 years
    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).
  • Wil
    Wil about 6 years
    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
    Wil about 6 years
    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
    Wil about 6 years
    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
    Wil about 6 years
    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.
  • Gregor y
    Gregor y about 6 years
    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
    Gregor y about 6 years
    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 developer.mozilla.org/en-US/docs/Web/HTTP/CORS
  • Gregor y
    Gregor y about 6 years
    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
    Gregor y about 6 years
    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.
  • Wil
    Wil almost 6 years
    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
    Wil almost 6 years
    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
    Wil almost 6 years
    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
    Wil almost 6 years
    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
    Wil almost 6 years
    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.
  • Gregor y
    Gregor y almost 6 years
    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
    Gregor y almost 6 years
    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?ce‌​rt1_accepted=yes&cer‌​t2_accepted=no&cert3‌​_accepted=yes
  • theAnonymous
    theAnonymous almost 6 years
    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.
  • Gregor y
    Gregor y over 5 years
    @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.
  • theAnonymous
    theAnonymous over 5 years
    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
    theAnonymous over 5 years
    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.
  • Gregor y
    Gregor y over 5 years
    @user3635998 yes 1000000 years 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 that nobody has thought of before then please do share.
  • theAnonymous
    theAnonymous over 5 years
    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.
  • Saber
    Saber over 5 years
    and then you can pass that document.location value to a REST service to get the certificate information.
  • umbreonben
    umbreonben over 5 years
    @JamesKPolk in fact it is a security problem, as websites can't detect if SSL has been broken and a fake cert being used.
  • President James K. Polk
    President James K. Polk over 5 years
    @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.
  • umbreonben
    umbreonben over 5 years
    @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.
  • President James K. Polk
    President James K. Polk over 5 years
    @aaa90210: Incorrect. That is what the browser does, not your javascript.
  • AlexV
    AlexV over 5 years
    @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...