2

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.

Community
  • 1
  • 1
Grinn
  • 5,370
  • 38
  • 51
  • 3
    Why not just have everything be HTTPS? You won't want your secure cookie being sent with HTTP transactions anyway, lest they cease to be secure cookies :-) – Pointy Aug 22 '12 at 16:05
  • 2
    Your question is essentially "how do I get SSL to work without SSL?" Well, you don't. – NullUserException Aug 22 '12 at 16:08
  • i believe you can share cookies across sub domains by setting the domain value to ".domain.com" – Jeff Wooden Aug 22 '12 at 16:20
  • @Pointy: HTTPS comes with overhead. I assume the cookie comment is in reference to "Bad Idea #1". The cookie would contain the private key that is used to encrypt future transactions. I wasn't saying that you would send the key with the transactions. – Grinn Aug 22 '12 at 16:39
  • @Grinn yes, HTTPS comes with overhead, but in 2012 it's not much of a price to pay for security. – Pointy Aug 22 '12 at 16:41
  • @NullUserException: Cute. So, you're solution is to have no security at all when not communicating over SSL? – Grinn Aug 22 '12 at 16:42
  • @JefferyAWooden: Provide that as an answer w/ a working example, FTW. – Grinn Aug 22 '12 at 16:45
  • @Grinn Yes. If you need secure communication, use SSL. – NullUserException Aug 22 '12 at 16:47
  • Hell, maybe you guys are right. Maybe if something isn't important enough to warrant SSL, it isn't important enough to secure at all. That doesn't sound right though. For example, this comment: You wouldn't want someone pretending to be you and making comments on SO all willy-nilly. But, this isn't over SSL. – Grinn Aug 22 '12 at 16:49
  • @Grinn, if you look at how SO works, it only secures authentication over ssl and once authentication cookie is set, rest communication is all non ssl. SO is a public site, all content is basically an educational content and it does not contain any private information. If you don't worry about ssl then why make web service calls in ssl either? Let all be non ssl or let all be in ssl, it is just easy by putting s after http instead of working on real complicated architecture unless you are going to paid a fortune and will be easy for others to maintain. – Akash Kava Aug 22 '12 at 19:20

3 Answers3

2

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.

AlexGad
  • 6,612
  • 5
  • 33
  • 45
  • Thanks Alex, but the non-OAuth approach is what I'm already doing. The trouble I am having is with establishing that initial private token. – Grinn Aug 23 '12 at 16:18
1

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

Community
  • 1
  • 1
Jeff Wooden
  • 5,339
  • 2
  • 19
  • 24
0

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.

Clomp
  • 3,168
  • 2
  • 23
  • 36