Encode/obfuscate HTTP parameters

18,311

Solution 1

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.

Solution 2

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;
}

Solution 3

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.

Solution 4

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.

Solution 5

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

Share:
18,311
OscarRyz
Author by

OscarRyz

Software Developer who happens to like writing code. Here are some interesting answers you might like to upvote :") Why java people frequently consume exception silently ? Coding in Other (Spoken) Languages How to create an string from the contents of a file History of Objective-C square brackets (as I remember it) ( visible only to >10k users )

Updated on June 05, 2022

Comments

  • OscarRyz
    OscarRyz almost 2 years

    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.