views:

149

answers:

6

We are currently working on a very simple Webapp, and we would like to "obfuscate" ( what would be the right term? ) or encode somehow the request parameter, so we can reduce the chance an idle user from sending arbitrarily data.

For instance, the url looks like /webapp?user=Oscar&count=3

We would like to have somthing like: /webapp?data=EDZhjgzzkjhGZKJHGZIUYZT and have that value decoded in the server with the real request info.

Before going into implementing something like this ourselves ( and probably doing it wrong ) I would like to know if there is something to do this already?

We have Java on the server and JavaScript on the client.

+14  A: 

No, don't do this. If you can build something in your client code to obfuscate the data being transmitted back to the server, then so can a willful hacker. You simply can't trust data being sent to your server, no matter what your official client does. Stick to escaping client data and validating it against a whitelist on the server side. Use SSL, and if you can, put your request parameters in a POST instead of GET.

Expansion edit

Your confusion stems from the goal to block users from tampering with request data, with the need to implementing standard security measures. Standard security measures for web applications involve using a combination of authentication, privilege and session management, audit trails, data validation, and secure communication channels.

Using SSL doesn't prevent the client from tampering with the data, but it does prevent middle-men from seeing or tampering with it. It also instructs well-behaved browsers not to cache sensitive data in the URL history.

It seems you have some sort of simple web application that has no authentication, and passes around request parameters that control it right in the GET, and thus some non-technically savvy people could probably figure out that user=WorkerBee can simply be changed to user=Boss in their browser bar, and thus they can access data they shouldn't see, or do things they shouldn't do. Your desire (or your customer's desire) to obfuscate those parameters is naïve, as it is only going to foil the least-technically savvy person. It is a half-baked measure and the reason you haven't found an existing solution is that it isn't a good approach. You're better off spending time implementing a decent authentication system with an audit trail for good measure (and if this is indeed what you do, mark Gary's answer as correct).

So, to wrap it up:

  1. Security by obfuscation isn't security at all.
  2. You can't trust user data, even if it is obscured. Validate your data.
  3. Using secure communication channels (SSL) helps block other related threats.
  4. You should abandon your approach and do the right thing. The right thing, in your case, probably means adding an authentication mechanism with a privilege system to prevent users from accessing things they aren't privileged enough to see - including things they might try to access by tampering with GET parameters. Gary R's answer, as well as Dave and Will's comment hit this one on the head.
Mike Atlas
So, your recommendation is *"Don't do it, because it not perfect"*? I don't really get how can I validate client data. For instance if the URL is `/getinfo?user=oscar` how am I suppose to validate against a white list the value: "Oscar". Wouldn't using SSL + POST be as easy to temper as not using them?
OscarRyz
@OcarRyz, for your example here you might want to sign the user into your application and use a session id stored in a cookie to verify their identity for future requests. Then when they try to view oscar's info you can validate that oscar exists, and that the user is either oscar himself, or someone who has permission to view oscar's info.
Dave Aaron Smith
I love this answer. Yes U should always validate on server side for correct input, no matter what! Plus, if u keep a lil bit of meaningful query string it gives a access to mash-up developers to do some interesting things on your website if he want to do!
Markandey Singh
@Oscar -- at a glance the problem you're dealing with here is not a data tampering problem, it's an authorization problem. Who cares if anyone asks for Oscar's info, if they're not authorized to see Oscar, then they get nothing. If that's the case, and your concern, need to do implement a full boat "roles and privileges" authorization scheme rather than trying to back hand preventing users from asking "bad questions" through hacking requests.
Will Hartung
I get more from Dave's and Will comments than from Mike's answer. I don't really know if Mike's answer imply those two comments in which case I would mark it as accepted. At least Will can edit Mike's answer to add the comment.
OscarRyz
ohhh, probably it is just me, but I didn't get it. What's the answer then? Use SSL and POST? what am I missing?
OscarRyz
I edited my answer to try to resolve your confusion, but I suspect that you really should be adding an authentication/privilege system rather than a URL-obfuscation system. The latter makes for a good http://www.thedailywtf.com post. Gary R's answer is probably the right one to accept.
Mike Atlas
@Mike Thanks for recommendation@Oscar You may want to check out this link http://static.springsource.org/spring-security/site/faq/faq.html which details the Spring Security approach to this problem
Gary Rowe
The answer is to do validation on the server. For instance, if the user is attempting to access Oscar's data, perform a check _on the server_ to ensure that they should be seeing Oscar's data before serving it to them. If they're trying to perform an admin-only option, don't just hide the button for non-admins, but _on the server_ check that they're an admin before performing that action.
Yuliy
A: 

You can encode data using base64 or something similar. I would encode the arguments inself in JSON to serialize them.

levu
+4  A: 

If your goal is to "reduce the chance an idle user from sending arbitrarily data," there's another simpler approach I would try. Make a private encryption key and store it in your application server side. Whenever your application generates a url, create a hash of the url using your private encryption key and put that hash in the query string. Whenever a user requests a page with parameters in the url, recompute the hash and see if it matches. This will give you some certainty that your application computed the url. It will leave your query string parameters readable though. In pseudo-code,

SALT = "so9dnfi3i21nwpsodjf";

function computeUrl(url) {
  return url + "&hash=" + md5(url + SALT );
}

function checkUrl(url) {
  hash = /&hash=(.+)/.match(url);
  oldUrl = url.strip(/&hash=.+/);
  return md5(oldUrl + SALT ) == hash;
}
Dave Aaron Smith
Very nice and clean !
oimoim
What do you mean "Whenever your application generates a url"? Do you mean "when a client generates a request"?
Mike Atlas
Dave Aaron Smith
That breaks pretty quickly if any of the parameters are from form input controls.
Mike Atlas
@Mike, very good point. I believe that anything other than the most simple forms would break any approach other than the more nuanced server side validation you discuss in your answer. A client side approach would be hackable with firebug and a server side approach other than what you describe would be useless.
Dave Aaron Smith
@jbinto, I don't quite follow. Nothing here is being decrypted. I'm generating and comparing hashes to ensure data integrity. Maybe part of the confusion is that I mislabeled PRIVATE_KEY. It should really be called SALT as in @Will's solution.
Dave Aaron Smith
I rename it as Salt :P
OscarRyz
A: 

Something like jCryption ?

http://www.jcryption.org/examples/

oimoim
Do I need a javascript intepreter in the server side?
OscarRyz
No, just have a look at the included php file (encrypt.php) and rewrite it in java :)
oimoim
+2  A: 

If the goal it to prevent "static" URLs from being manipulated, then you can simply encrypt the parameters, or sign them. It's likely "safe enough" to tack on an MD5 of the URL parameters, along with some salt. The salt can be a random string stored in the session, say.

Then you can just:

http://example.com/service?x=123&y=Bob&sig=ABCD1324

This technique exposes the data (i.e. they can "see" that xyz=123), but they can not change the data.

There's is an advantage of "encryption" (and I use that term loosely). This is where you encrypt the entire parameter section of the URL.

Here you can do something like:

http://example.com/service?data=ABC1235ABC

The nice thing about using encryption is two fold.

One it protects the data (they user can never see that xyz=123, for example).

The other feature tho is that it's extensible:

http://example.com/service?data=ABC1235ABC&newparm=123&otherparm=abc

Here, you can decode the original payload, and do a (safe) merge with the new data.

So, requests can ADD data to the request, just not change EXISTING data.

You can do the same via the signing technique, you would just need consolidate the entire request in to a single "blob", and that blob is implicitly signed. That's "effectively" encrypted, just a weak encryption.

Obviously you don't want to do ANY of this on the client. There's no point. If you can do it, "they" can do it and you can't tell the difference, so you may as well not do it at all -- unless you want to "encrypt" data over a normal HTTP port (vs TLS, but then folks will wisely wonder "why bother").

For Java, all this work goes in a Filter, that's the way I did it. The back end is isolated from this.

If you wish, you can make the back end completely isolated from this with an outbound filter that handles the URL encryption/signing on the way out.

That's also what I did.

The down side is that it's very involved to get it right and performant. You need a light weight HTML parser to pull out the URLs (I wrote a streaming parser to do it on the fly so it didn't copy the entire page in to RAM).

The bright side is all of the content side "just works", as they don't know anything about it.

There's also some special handling when dealing with Javascript (as your filter won't easily "know" where there's a URL to encrypt). I resolved this by requiring urls to be signed to be specific "var signedURL='....'", so I can find those easily in the output. Not as crushing a burden on designers as you might think.

The other bright side of the filter is that you can disable it. If you have some "odd behavior" happening, simply turn it off. If the behavior continues, you've found a bug related to encryption. It also let developers work in plain text and leave the encryption for integration testing.

Pain to do, but it's nice overall in the end.

Will Hartung
+2  A: 

If you're trying to restrict access to data then use some kind of login mechanism with a cookie providing a Single Sign On authentication key. If the client sends the cookie with the key then they can manipulate the data in accordance with the authorities associated with their account (admin, public user etc). Just look at Spring Security, CAS etc for easy to use implementations of this in Java. The tokens provided in the cookie are usually encrypted with the private key of the issuing server and are typically tamper proof.

Alternatively, if you want your public user (unauthenticated) to be able to post some data to your site, then all bets are off. You must validate on the server side. This means restricting access to certain URIs and making sure that all input is cleaned.

The golden rule here is disallow everything, except stuff you know is safe.

Gary Rowe