I'm curious if there's any way that a server can validate a client without knowing that the client is entirely "friendly" code that isn't monitoring 1) the user's input or 2) network requests.
The only way I could conceive of this is if browsers have a built-in, secure, isolated shell / scope that can hash and send data (which can be verified with a complimenting server unhashing / lookup script).
Is there any browser-supported (non-DOM) input/hashing method that can also be installed on the server to identify the authenticity or user input? I want to avoid Chrome Extensions and potential keylogging in general, but I'm not sure any browser supports this feature.
Thanks
EDIT
I think some form of 2-step auth in a separate window would be the closest, but I don't have SSL, and I don't like the presentation of random "popup" windows
If I understand your question correctly you are asking for a proof that the data entered into a form are neither manipulated nor generated by malicious software. But you (as operator of the server) don't have control of the client.
This is impossible as long as you don't have control of the client because it is impossible to distinguish user generated data from software generated data on the network level, and that's all you get at the server. Even the output generated by a browser extension can be faked.
I think some form of 2-step auth would be the closest
2FA is relevant for authentication of the client only and provides no way of making user generated data tamper resistant.
SSL alternative for secure handshake?
SSL only protects the transport and does not prevent modification of the user input within a malicious browser extension or similar. It also does not protect against malicious man in the middle on the clients machine (i.e. Superfish or similar).
Related
My company is looking at using card based certificates (like CACs) for authentication on a web site; instead of the user entering a username and password this information would be extracted from the certificate. How does one go about programming the front end to pass the certificate on to the webserver? I've been looking for specific directions but wind up with everything but that. The over all idea is to hook into something like an LDAP for authentication eventually, but the browser part is completely eluding me.
You don't really have to do much in the way of the client side stuff. For a website, the browser handles it for you. You just have to setup your server to require a client certificate and the browser will handle it. Under Apache, after setting up the SSL certificate, this is as simple as setting SSLVerifyClient required (manual) in the apache configuration. Your site will then require a client certificate for access. You can also set SSLVerifyClient to optional which allows someone to click "Cancel" when prompted to select a certificate and the site will still load, but is missing the environment variables (see below).
If you are using smart cards, you might need a driver for the smart card reader to prompt the user for a pin to query the card, but it isn't something you need to handle. In my experience (with CAC cards), both Internet Explorer and Firefox use a third party software (we use ActiveIdentity) to ask for the user's pin (Firefox needs to be setup to use a "Security Device", but it is simple) and Chrome already has built in support for the smart cards without needing a separate program. It is also possible to install the certificate in the browser, but I haven't worked with that.
As for validating the user, in Apache, once the SSL handshake stuff has been completed by the browser and server, in PHP there are several environment variables that are available (you can see them on a phpinfo() page or if you print_r($_SERVER). They are all SSL_* and include stuff like the domain or common name). This can differ based on what information was supplied from the client. We just found one that held a unique id for the card $_SERVER['SSL_CLIENT_S_DN_CN'] and store that with each account. Then we can use that id to query for the account for creating a validated user session.
SSL client certificates are presented in the SSL handshake, which is done in the lower layers and is therefore transparent to the frontend (browser handles it internally). The web server needs to be configured to accept or require the client certificates so they are requested in the SSL handshake.
The client certificate is then validated by the web server and you can then access the client's identity typically via some API, depending on the server/platform.
EDIT:
Here's a guide for nginx/PHP: http://nategood.com/client-side-certificate-authentication-in-ngi
I would like to create a web app that:
takes in personal data (including SSN) using a csv
processes and manipulates the data in the browser javascript
outputs a pdf
Since everything happens in the browser and none of the data is stored in a database at the web host does an SSL certificate provide sufficient security?
The SSL certificate only helps that the script is securely send from your server to the clients browser and that no manipulation can be done in between. It does not help against
Manipulation at the server side. It is actually very common that servers gets hacked and the stored applications gets modified for delivery of malware and similar.
Client-Side Cross-Site-Scripting attacks, i.e. DOM XSS. Since what you do is fairly complex chances are high that you fail to protect against such an attack.
Other Cross-Site-Scripting: if the script you serve to the user depends on the user, cookies or whatever (that is not a static script) you might be vulnerable to other XSS attacks too.
So in general the answer is that SSL is not sufficient alone.
In order to connect to a third party application, I have to give my users the capability to select one of their installed SSL client certificates and transfer it to the third party which is used by the application server. (My web application does not require SSL, it is the third party that require SSL certificates).
It seems to me that access to this list of certificates is only possible by the browser itself when connecting to a service that require SSL. Is it possible to launch the same dialog box through Javascript or is there any way for a web application to browse the SSL store of the end-user ?
If it is not possible, can I simply open a file dialog box and upload the client certificate as any standard file ?
I have to support any browser from IE9 and no plug-ins are allowed in our application.
Thanks.
If it is not possible, can I simply open a file dialog box and upload the client certificate as any standard file ?
Firstly, that's not the way SSL/TLS client authentication works at all. It's simply not a matter of uploading the certificate. The private key matching the certificate is used to sign some content (in the CertificateVerify TLS message) during the TLS handshake. That's what performs the authentication.
Coming back to your main question, for security reasons, the SSL/TLS stack is handled outside the scope of the JavaScript code. Selecting the client certificate is part of that.
You could potentially have some sort of API to let the JavaScript code access some of the cryptographic features of the browser (and there has been work in this area). However, there would be security considerations to take into account.
Even if certificates only contain public information to some extent, that doesn't mean it's public information that is to be distributed to anyone in the world, at least not necessarily in conjunction with the act of browsing any website.
If you had the ability to list the user's list of certificate from the JavaScript code sent by your server, you'd certainly have the ability to send that list back to yourself almost transparently with an Ajax call. While some people are concerned about the privacy implications of being tracked by cookies, being tracked by which client certs you may have takes this to another level (e.g. Subject DN with CN=John Smith and Issuer DN with CN=Department/Ministry of Health/Defence: that would be a bit of a giveaway).
My web application does not require SSL, it is the third party that require SSL certificates.
Here, you're not saying whether that third party is accessed directly by the user's browsers, or if you expect the users to delegate their credentials for you to interact with that third party (without direct user involvement).
If the users have direct access to that third party (via another request), their browser should prompt them for the certificate they with to use.
If it's about credential delegations, that's another problem entirely, since users you never give you the private key for their own client certificate to be able to sign in their name. (It's might be technically possible for users to just give you their PKCS#12 file, for example, but it defeats the point of putting up in place this sort of authentication in the first place).
There has been work done about authentication delegation with certificates using proxy certificates (RFC 3820). Essentially, your EEC (End-Entity Certificate) is used as a mini-CA, despite not having the CA flags, to issue a short-lived certificate with the remote party will accept. This sort of mechanism is generally not well integrated in browsers.
Another, more realistic approach, would be to look into the world of SSO, SAML and Shibboleth, for example. That does work with existing browsers, but the overall architecture is a bit different (so you'll need to discuss that with the third party).
The certificate isn't part of the DOM, so no, this won't be possible.
In a browser environment, is it possible to obtain list of SSL certificates in JavaScript?
The WebCrypto API allows you to discover some things, like shared and derived keys. But looking at their charter and use cases, its not clear to me if they allow enumeration and discovery of certificates.
I see it was discussed in the past and an issue was raised. Here's the discussion: Crypto-ISSUE-15: Discovering certificates associated with (private) keys. But I can't find anything on Issue 15 in the WebCrypto Tracker.
Also see Will the WebCrypto API allow discovery/enumeration of certificates? question on the WebCrypto Mailing list. Hopefully there will be a simple, YES/NO answer.
But don't be surprised if its not available through WebCrypto. The browser security engineers have a particular way of looking at things, and that usually does not include client certificates. Client certificates would effectively stop MitM attacks (see, for example, Origin Bound Certificates), and browsers don't make stopping MitM a priority. Instead, they are OK with mishandling credentials like passwords; and they opt for a One Time Password (OTP) using U2F.
In a reality stranger than fiction, the browsers will even (1) use Public Key Pinning for HTTP, and then (2) break a known good pinset because the user was phished! You can't make this stuff up...
Here's the idea:
If I can get something unique about a computer with JavaScript from an HTML page (probably the MAC address), then can I use this data as another security check?
Is that possible?
I am not going to check the computer at client side, i am going to send it to server to check. If nothing sent, user will be blocked. So it is not something that any developer+firebug combination can bypass. I just want to send one more string with username and password which is unique to computer and no one else knows if they don't entered to the system from that computer. Like a password hidden from user itself.
You can try using a tracking cookie; note however that such mechanisms are considered transient (e.g. cookies can be erased). In-browser JavaScript is sandboxed so that it does not have access to components outside the page. Note also that any feeling of security you'll gain with JavaScript is illusory - the script runs on the client side, where it can be modified (therefore there's no way to tell whether the "unique" piece of data is genuine or faked) or disabled altogether.
If you're trying to prevent random people from hacking at your app, you may want to ban them after a certain number of failed attempts. This will not get you any security, it's more of a flytrap - it limits the annoyances somewhat.
Finally, if you want actual security, go for HTTPS with real (NOT self-signed) server certificates and client-side certificates - see e.g. this for an implementation (that example, however, uses self-signed server certificates, which is not very secure). This is a mechanism that is well-implemented in the browser itself, and provides you with a somewhat secure system (complete with a secure keystore) of identifying your users (as opposed to a fundamentally flawed JS "security", or relying on user-readable files). Oh, and your data is encrypted while on the wire, that's a bonus.
SSL actually does what you're asking for: verifies that the client machine has a certificate issued to that user. This mechanism works inside the browser, not just inside the webpage; thus, it is much harder to subvert this than an in-page JavaScript. It stores a large unique identifier (clientside certificate) in a secure way, and it can prove to the server that it actually has that identifier - which is pretty much your initial requirement.
(Incidentally, using SSL, the data will be protected in transit, and the client can validate the server's identity; those weren't your requirements, but they're more or less necessary to assure that you're actually talking to the real client and real server)
JavaScript within a Web browser executes within a sandbox and has no access to the underlying hardware. Besides, MAC addresses aren't guaranteed to be unique.
No. And you shouldn't implement security with JavaScript only as any competent developer with Firebug will get around it in no time.
How can a user, using one of the major modern browsers, know for sure that he is running my unmodified javascript code even over an untrusted network?
Here is some more info about my situation:
I have a web application that deals with private information.
The login process is an implementation of a password-authenticated key agreement in JavaScript. Basically during login, a shared secret key is established between the client and the server. Once the user logs in all communication with the server is encrypted using the shared key. The system must be safe against ACTIVE man-in-the-middle attacks.
Assuming that my implementation is correct and the user is smart enough not to fall victim to a phishing attack there remains just one large hole in the system: an attacker can tamper with my application as it is being downloaded and inject code that steals the password. Basically the entire system relies on the fact that the user can trust the code running on his machine.
I want something similar to signed applets but I would prefer a pure javascript solution, if possible.
Maybe I am misunderstanding your problem, but my first thought is to use SSL. It is designed to ensure that you're talking to the server you think you are, and that no one has modified the content midstream. You do not even have to trust the network in this case, because of the nature of SSL.
The good thing about this approach is that you can fairly easily drop it into your existing web application. In most cases, you can basically configure your HTTP server to use SSL, and change your http:// requests to https://.
This is an old, open question but the answers seemed to not do this justice.
https:// provides integrity, not true identification nor non-repudiation.
I direct you to http://www.matasano.com/articles/javascript-cryptography/
Don't do crypto in JS, because a malicious injected script can easily grab passwords or alter the library. SJCL is neat, but it offer a blatantly false sense of security (their quote, and quoted by above)
Unfortunately, this is not as great as in desktop applications
because it is not feasible to completely protect against code
injection, malicious servers and side-channel attacks.
The long-term issue is that JavaScript lacks:
Uniformly working const
The ability to make objects deeply const and not reprototypable.
Code-signing
// codesign: cert:(hex fingerprint) signature:(hex MAC)
Certs would be managed similar to CA certs. MAC would be used with appropriate sign/verify constructions.
Crypto, clipboard stuff are reasons to have JavaScript native plugins (signed, of course)
Getting JavaScript engines to all implement a standard is another thing, but it's doable an it's absolutely necessary to end a large swath of malware.
You could have an external Javascript file which takes an MD5 hash of your login JS, and sends an Ajax request to the server to verify that it is correct and up-to-date. Use basic security or encryption practices here - public/private keys or some other method to be sure that the response came from your server.
You can then confidently display to the user that the client-side scripts are verified, and allow the login script to proceed.