I'm working on a new site that utilizes a service-oriented architecture, with pure JavaScript on the front-end, accessing web services for data via RESTful AJAX calls.
It shouldn't be of particular importance but my stack is:
javascriptMVC
jQuery
Bootsrap
ASP.NET Web API (C# on .NET 4.0)
MS SQL
From this article I've figured out some good ways of securing my web service calls once I have a private key shared between the client (JavaScript) and server (REST services via Web API). However, I'm struggling with how to establish the private key to be used for encryption.
Bad Idea #1
The initial though was to set it at log in which would occur over HTTPS, then store it on the client in a cookie for reuse. The problem is that our SSL cert is for https://secure.example.com, while our site is on http://www.example.com - so I wouldn't be able to access the secure.example.com cookie from www.example.com.
Bad Idea #2
My next thought was to pass it encrypted and signed via a URL parameter from the HTTPS login to the HTTP post-login page like so:
http://www.example.com/processLogin?key=[encryptedKey]&sig=[encryptedSig]&user=[userid]
encryptedKey and encryptedSig would both be encrypted with another private key that only exists just for that transaction. It would be created at log-in and assigned to that user in the database. On the HTTP side, all of this gets passed to the server which decrypts it, validates the signature, removes that private key (to guard against replay attacks - essentially a nonce) and returns the decrypted private key ([encryptedKey] decrypted).
From then on out, the decrypted value of [encryptedKey] would be used for all future transactions. The problem is that the decrypted private key would have to be sent over the line via HTTP, which sucks.
Bad Idea #3
It also briefly occurred to me to have a hard-coded key in the JavaScript that's used to decrypt this value but no matter how I try and obfuscate it, it could be found and used by a hacker.
Bad Idea #4
I've also considered some sort of key exchange using Public-key cryptography at the initial handshake, but as noted elsewhere, you can't really be confident on the client-side that there isn't tampering during this initial handshake unless it's over SSL - putting me back at square one.
The Big Question
So, how do you guys manage such things without everything going over HTTPS? Do I have to have the same domain name for my HTTP and HTTPS so that I can store this private key in a cookie?
Note that the non-SSL portions of the site wouldn't be sharing credit card or login information or the like. I just don't want to leave this sucker wide open.
You can not have secure and encrypted communication between a javascript client and a server without implementing SSL. It is impossible. If what you really want to accomplish is not to encrypt the traffic but simply insure the client you are talking to has been authorized to make the request and that the client is not an impersonator, then OAuth may be sufficient. See http://www.dotnetopenauth.net/ for the standard OAuth .net implementation.
If OAuth is not what you want to get involved in and you simply want to build on what you already have built, you should distribute a token and a public and a private key to the javascript client. The public key and the token is what gets sent back and forth for every request while the private key is never sent back and forth and is instead used to generate some type of signature hash. Every request should have this signature and a time-based nonce to prevent replays. You should also expire the token on a very frequent basis and require the client to request a "refresh" token with their sig and their public key. In essence, what I have described is OAuth 1.0a, and if you do want to take this route, I would refer back to DotNet OpenAuth instead of trying to roll it yourself.
However, to reiterate, without SSL, you will still be vulnerable to other types of attacks. Also, unless you SSL encrypt the initial token request, a hacker could always sniff the initial delivery of the token/public/private key pair, therefore, eliminating all your hard work to make things secure in the first place.
An alternative to the above is to have a proxy server sitting between your client and the REST API. Requests to the API can only go through the proxy server. The client logs in and gets a cookie from https://secure.example.com using basic auth. The client then continues to make requests to secure.example.com and secure.example.com then makes requests to your API and returns the data back to the client.
Anyway, hopefully enough info to give you food for thought.
You can view how to work with sub domains and cookies by checking out this answer: Creating a javascript cookie on a domain and reading it across sub domains
Regarding Bad Idea #3:
I've known for awhile that I can use http://jsbeautifier.org to deobfuscate anything that is obfuscated using http://dean.edwards.name/packer/ with the "Shrink variables" checkbox &/or the "Base62 encode" checkbox. So JavaScript is totally insecure & shouldn't be relied upon for saving any sort of SSL encryption, nor user auth tokens, nor editable account stats in the browser. Otherwise someone would simply try to edit their game account & give themselves +10 million game coins.
When everything goes over SSL it only protects against "man-in-the-middle" attacks. It's really a "server-bot-in-the-middle" attack. It doesn't prevent the end-user from being a hacker themselves.
In this next illustration, SSL would prevent servers a through e from seeing any data that's being passed from the client to the terminus server, but without SSL server C would steal data. This is how server hops work, without encryption, where the client + all servers can read the data:
client > a > b > server c's bot sniffs http traffic > d > e > terminus server
Server c's bot logs a credit card number, which is an encrypted bank account number. (Most people don't realize that a credit card number is an encrypted & transformed bank account number. If the credit card number is compromised, it's easy for a bank to re-issue a new encrypted CC# from a bank account number & send out a new card in the mail. They don't have to change the original bank account number nor printing new checks, which have the bank account number printed on the bottom of them.)
Server hops with TLS/SSL/https encryption would work like this, where only the client & server could read anything:
client > all servers from a-e are blind & pass the data through > terminus server
Server c's bot sees junk like: as65a89as7df08 instead of 1234-5678-9012-..., if they can read anything at all using SSL.
What's cool about iOS, is that it makes it harder to read the JS code when it's used with HTML 5 & CSS. User can't right-click to inspect on their iPhone, like they can in a desktop browser. It's easy to hide a password in the terminus server using a back-end language.
It's currently impossible to prevent JavaScript from being hacked by the end-user (client). Every end-user can be a hacker. If I figure something else out, I can post it here for future developers to read.
Related
We're in the process of migrating our MVC-based server application and making a REST-ful API through which calls will be handled.
I've been reading up on AES encryption and OAuth2 and decided to implement a solution grown form those concepts as follows:
Client sends a request to log in providing a UserID or Email. This request is HMAC'd using an API Secret Key.
The server checks if the UserID/Email matches an existing account and if it finds one, creates and stores a server nonce which it sends as part of the response to the client.
The client creates their own client nonce and creates a new temporary key from the API Secret key and both nonces. It then sends a login request with a password encrypted using this temporary key [for added entropy and to avoid ever sending a password in plaintext].
The server decrypts the password and HMAC using the latest nonce it has stored for this client on this platform [a mobile and a web client can have their own distinct nonces and sessions] and the client nonce which was sent in the clear, if the HMAC checks out it then validates the password against the database [PBKDF2 hashing and salting].
If the request is valid and the password and UserID match records, a new Session Secret Key is created for that UserID on that platform and this Secret key is sent to the client and will be used to HMAC every API request fromt hat client henceforth.
Any new non-login request would include an HMAC signature computed from the Session Secret key and randomized IV's.
All communication is handled through TLS so this is added security and not the only line of defense.
On the mobile apps this would work since you can hide the Mobile App's Secret Key on a config file and this gives some decent measure of security - [perhaps not a lot I'm not fully sure] but if we try to convert all the requests from our webpage to this form this would mean using Javascript to handle the client-side AES encryption and authentication and ... well as this article clearly explains, " if you store your API key in a JavaScript web app you might as well just print it out in big bold letters across the homepage as the whole world now has access to it through their browser’s dev tools."
I could use only the nonces as the API Secret key -- or forgo using AES encryption for those requests altogether and try to validate through other means such as CSRF tokens and making sure all the requests come form our own front end in some way - but this wouldn't work if we wanted to create an API that allows integration with other pages or services and even then, how would I go about securing the client's secret Session key?
The article suggests generating single-use cookies as a tokens but that's a limited solution that works for the poster's services but wouldn't for us. I want to be able to HMAC every request the user sends with a user-specific key that can expire and be reset and since the service will eventually handle money, I want request authentication to be locked down tight.
So what are my options?
Do I just ditch Javascript since it is doomed? Is there some way to store a secret key without exposing it clear as day hardcoded into the .js script? Should I generate a new temporary Secret key to be used for login calls only and send that to the user when they request the server nonce?
Also, the post I linked to first suggests using a cookie to store the Session key for the client and then access the key from JS. Is this ok or would that provide more holes than it seals?
It's good to know which measures prevent which security holes.
You are correct that JavaScript is not well suited for encryption because there is no place to store a secret. There are also no good encryption libraries because you shouldn't be doing encryption in JavaScript.
The session key can serve as the authentication key. If you're using TLS your connection is secure and an attacker can't know the session key.
Additionally, JavaScript doesn't need to know the session key. Cookies, by default, are sent with every request. And you can set the cookie to be an http-only cookie. You don't have to do this, but it does add another layer of security.
You can give the session cookie a very long expiration time so that it essentially works like a secret API key. The browser will take care of storing the cookie securely. It is advised to rotate the session key often, typically at the start of every new session and when authentication information changes (like a password reset).
CSRF-tokens prevent replay attacks. It's definitely recommend to secure a modification request with a CSRF-token. You don't need a CSRF-check for every request, just requests that modify sensitive information (such as your login credentials, or in your case: transactions).
For CSRF-tokens you can use the same approach as the session key: store it in a cookie.
The key part is that JavaScript doesn't need to know about any of this.
One important thing that I'm sure you realize as well is that any keys or nonces you generate must be cryptographically safe. Don't use low entropy functions.
So:
You don't need to encrypt the userid or email, TLS does that for you already. Additionally you can send the password as well, you don't need to send it separately in step 3. We're not going to do any encryption in JavaScript. All encryption is handled by TLS/HTTPS alone.
If you have a separate authentication server (like a single sign on), this approach is fine. Else you can skip this step.
You don't need this.
The server doesn't need to decrypt anything, encryption is handled by TLS. How you store the password is a topic on it's own but I think you've got it.
Ok. Again, the client shouldn't encrypt anything.
Send just the session key. It's is enough.
Revised is:
Client sends login credentials. Connection must be secure.
Server verifies credentials and sends authentication token as cookie and keeps track of the authentication token is a session list.
For every request:
Client includes authentication token. This happens automatically if you use cookies.
Server verifies authentication token and possibly generates a fresh token that the client will use from then on.
Mobile apps should be considered as public clients. This means they should not store any secret. Whatever the encryption algorithm you will use, nothing prevent the client credentials from being compromised.
That is why the OAuth2 Framework protocol defines the Implicit grant type flow which allow public client interaction and do not need any client authentication. You may also consider the RFC7636 to protect the issuance of the access token.
I would like to encrypt ajax post and get request with javascript.
The flow should be -
Server generated private and public key on request
Server sends the public key to client
Client encrypts the data with public key
Sever decrypts the data with the private key
I know SSL is an option, but my application is a small plugin which can be installed on any website that allows a user to purchase products on that website. Is there a way i can encrypt all the data at front end and decrypt at back end.
Thanks in advance!
Generally speaking, in browser cryptography can be considered a bad idea. Sending the data over ssl-tls would likely be much more secure than a home-brewed crypto solution, like you seem to be suggesting. This can be considered especially bad when transmitting data like credit card info, as it appears you will be.
http allows for extremely easy man in the middle attacks to eavesdrop on any data being sent either way, so there would almost certainly be no secure way to transmit the keys in the first place, let alone the secure information.
If you really really want to go this route, then have a look at crypto-js.
This is not a good idea, and you should use SSL. Probably hence the downvotes.
Considering your use case, the best way to do this would probably be to host your own central service with SSL enabled, and route all ajax requests to your service, not theirs. Their servers could then poll your server using your SSL certificate, to view any relevant information. So you would be acting as some sort of centralised API, with both the clients and businesses connecting. You still need to consider however, that any information sent in the clear, ie over http, not https, can be tampered with before it reaches the user.
As far as I am aware, no, you cannot generate SSL certificates on the fly.
CryptoJS has functions to create HMAC from a message and the secret key.
How can this be secure considering that the secret key must be stored in plain sight in the JavaScript source deployed on the client ?
Anyone can take the key and issue similar requests to the server under the identity of the original client of the API. Isn't "identity" the problem that HMAC is supposed to solve ?
All in all, I do not understand the purpose of HMAC in client side JS since the key can't be kept secret.
Is there a use case to computing HMAC in JavaScript ?
JavaScript now has WebRTC where two clients can communicate peer-to-peer, this would be a scenario where clients can generate and use their own "secret".
There are some cases where client -> server could be usable as well. If your server was "dynamically" serving the JavaScript then it could insert a "secret" based on the clients current session/login. Assuming you are using HTTPS (if not there could be a man in the middle slurping up the "secret") then it's not unreasonable to assume that communication to the server signed with that specific "secret" (even over unsecured HTTP) belongs to only that client.
How can this be secure considering that the secret key must be stored in plain sight in the JavaScript source deployed on the client ?
Each client should get their own key/secret which enables them access to the resources they are supposed to have access to. This is effectively no different than a user knowing their own username and password. Their user/pass combo only allows access to the resources they need. The same should go for the key pair.
Anyone can take the key and issue similar requests to the server under the identity of the original client of the API. Isn't "identity" the problem that HMAC is supposed to solve ?
Yes, of course if someone gets your key and secret they can issue requests as if they came from you. Simply don't give out your secret to others. Having it in JavaScript doesn't matter at all. Sure, the user can see it but unless they take that key and secret and put it somewhere else, it isn't a problem.
I have a system where a user logs in through normal means (username/password, OAuth, OpenID, etc.) and is immediately issued a key/secret for making API calls. The client-side application uses this key/secret to actually do its work. The issuance of this key/secret is done over HTTPS. I wanted to use HMAC for my API since I wanted the user to be able to pre-sign requests to be used in the open. This method enables me to keep HMAC for the usual administrative GUI as well.
Cryptico seems like a super slick RSA encryption library.
cryptico.wwwtyro.net
In regards to JavaScript applications, suppose I want to send data to the client, have them do something to the data, and pass it back. How can I use RSA to ensure that the data clients send back to the server is not tampered with? Since JavaScript is easily reverse-engineered, is there any practical client-side application of cryptico?
Do you - by your example - mean that you want to hide from the user what his client is doing with the data? If so - it's impossible.
You should never trust any data which comes from the client.
If you send encrypted data to the client to process - you must assume that the user knows (or will know if he wants) the encryption key, otherwise it will be impossible to process. In other words there is no secure way to hide from the user what his client processes. Obfuscation - like you've noticed can always be cracked no matter what language you use.
I think that the most common and practical client-side application for this library would be encrypting user's data and sending them to server or vice-versa. There may be some cases you can't use SSL. Moreover, you can make -for example- an encrypted post on facebook which only your friend will be able to decrypt (because he knows the key).
There is a solution to what you seek (I'm sure there is more than one). My answer requires two non-conventional approaches to what we call a 'secure connection' and how you receive the 'client code'.
You need a physically pre-shared key that initiates a secure connection, and because it's pre-shared it doesn't have to be RSA, which then opens up speed opportunities and higher levels of encryption security for you.
Physically pre-share your client code in a similar manner, i.e., download the code from a cd in a magazine or from a pre-paid card sold in a market. This stops the MITM from sending you tampered and exploited clients, which ssl allows. Once client is known to be secure, and a real secure connection, mentioned in (1), is established, the client code can be updated.
With the combination of a pre-shared key that develops a secure connection and client code that can pass a checksum, you can achieve what you are after.
Ideally, we should have pre-shared secure connection keys available in the market now, but we don't. So, for you to do it alone, would require to implement something similar for you website specifically until people in this country get their act together with some real security. You would have to give them keys over your phone, through the mail, etc. And your client code would most likely have to be a browser extension to install it due to cross domain security issues.
I like the way Google Maps' api is consumed, using a script include, but I'm worried:
My api is "semi-private", that is, accessible over the internet but should allow for secure transmission of data and some kind of authentication. The data should remain private over the wire, and one consumer shouldn't be able to get at another's data.
How can I use SSL and some kind of authentication to keep the data secure, but still accessible "horizontally" from a plain HTML page with no server-side proxy required? Do I need to manage keys? How will the keys be posted to the server without being intercepted? Can I use OpenId (or some other 3rd-party authentication) to authenticate api users, or do I have to create my own authentication mechanism? I've been all over Google and can't find a good guide to designing and deploying my API securely.
Right now I'm using REST and AJAX to consume them, but cross-domain calls are impossible. Any help or a pointer in the right direction would be much appreciated.
I'd probably use a dynamically-generated script tag with an SSL URL that included a key in the query string that was public-key encrypted. The server would use the private key to decrypt the query string parameter and return script that included the relevant information (or didn't, if the key was invalid). Or something along those lines. But I'll admit that I haven't actually had to do it in practice.
I'd also look for prior art, like Amazon's S3 service.
So:
User provides secret
Client-side code uses public key to encrypt the secret
JavaScript appends a script tag that includes the URL
Server handles the script request, decrypts the secret, checks it, and sends back the relevant response.
You may well need two cycles, because otherwise the request to the server could be re-used via a man-in-the-middle attack. That would be:
JavaScript appends a script tag that requests a unique key (probably with some confounding information, like the source IP and some random further key)
Server responds with a one-time key tied to that IP
User provides secret
Client-side code uses public key to encrypt the secret, including the unique key from #1
JavaScript appends a script tag that includes the URL
Server handles the script request, decrypts the secret, checks it, and sends back the relevant response.
The response could well be encrypted (to some degree) using the random key included in #1
None of which I've actually done. (Or have I? BWAa-ha-ha-ha...) FWIW.
OAuth might help with this situation by having the user login to the 3rd-party application and allowing your application to access the 3rd-party on their behalf by using a request token when you make xhr requests. http://oauth.net/documentation/getting-started/
========
The reason for using a server-side proxy boils down to the Same-origin policy built into web browsers: http://en.wikipedia.org/wiki/Same_origin_policy
Essentially the browser only allows requests to be made to the address in which the page comes from (e.g. facebook.com can only make requests to facebook.com URIs). A server-side proxy solves this issue by making requests to servers outside the current origin. Server-side proxies are also the best practice for making requests like this.
Check out the opensource javascript Forge project. It provides a javascript TLS implementation that allows secure cross-domain xhr requests. It might be of use to you:
http://digitalbazaar.com/2010/07/20/javascript-tls-1/
http://digitalbazaar.com/2010/07/20/javascript-tls-2/
https://github.com/digitalbazaar/forge
One potential solution:
Set up an Apache server to run your site.
Get an SSL certificate for your site.
Install the apache mod that comes with Forge to setup a cross-domain policy that allows other sites to access yours.
Host Forge's TLS implementation on your site along with your site's certificate in PEM format.
Tell other sites to include the javascript from your site and use it to make secure calls to your site to do whatever it is you want to.
(3rd party) Page uses OAUTH or something similar to authenticate the user and get a token from your server.
Page loads an IFRAME from your server via SSL passing the token along for authentication.
The IFRAME can communicate securely to your server via SSL
Use easyXDM or something similar to communicate between the IFRAME and the 3rd party page, using some limited RPC-like or socket-like API you create.
Or if you really don't trust the third party - do your authentication inside the iframe (no need for oauth then, just use a plain html form) and communicate anything the outer page needs to know about the user using easyXDM.
Not too sure of what the question is exactly, I take it you're attempting to do a jsonp-like call to [https://secure.com] in order to process/display data on [http://regular.com]?
Can the two servers talk to each other? How about something like this:
User logs in on [https://secure.com]
Upon authentication, secure.com generates an token (lets call it syntoken) and passes it directly to regular.com (server-to-server), maybe like a session_id, some arbitrary message, and an otp cipher (lets call it syncipher).
Broswer receives a session_id cookie, and Secure.com then redirects the browser to http://regular.com/setcookieandredirect?session_id=blabla&otpencryptedsynmessage=blabla
Regular.com looks up otp cipher using session_id as a key, and decrypts otpencryptedmessage "blabla."
If decrypted message matches the original message in the syntoken, we can verify user is logged in [regular.com] and regular.com generates another token (lets call it acktoken, lolz) and passes it directly to [secure.com], consisting of session_id, some arbitrary ack message, and a different otp cipher (lets call it ackcipher).
Regular.com then sends the browser a cookie consisting of otpencryptedackmessage (let's name this cookie "verified_session").
Finish loading the page.
From there, you can do jsonp-like calls to
https://secure.com/getscript.js?query=dataname&verifiedtoken=(verified_sessions_cookie_value)
where secure.com/getscript.js will take the verifiedtoken, lookup the ackcipher based on the original cookie session_id sent by [secure.com] as the key, and decrypt the otpencrypedackmessage. If the decrypted message matches the ack message, render the script file.
It's kinda like a 3-way handshake. The secret sauce is that the servers have to be able to talk to each other directly to pass secret keys discretely. You don't have to use the same session_id for both servers, I was just using that as an easy point of reference to find a way to access the syn/ack otp ciphers. The ciphers must be completely hidden from public.