Encrypt passed URL parameters

Hi,

I’ve been working on a website for a small telecoms company that will allow it’s customers to view their bills online. The site allows for call itemisations, summary bills and on-the-fly PDF invoices. I think i’ve done quite well on it considering im fairly new to PHP.

The thing is at the beginning of the project I sussed out (not very hard) how to send variables from one page to another, great. But in the case of this website, some of the information being passed could be tampered with and potentially lead to misleading information.

I am currently using the base64 method to ‘scramble’ the parameters being passed, which is fine at the moment. In the future, we wish to allow customers to pay their ADSL and telephone bills through the website. I was wondering if anyone knew of better ways to encrypt the parameters being sent over the URL and how to decrypt them on the next page.

Basically, just to make the site more secure.

Like I said, I use base64_encrypt on the page which is passing the URL strings and then base64_decrypt to receive the variable and decrypt it, so the parameters can then be used in an SQL query.

Thanks in anticipation.

Why are you using URL params rather than session variables? have a read through http://phpsec.org/library/ for help on creating a secure session authentification system

Hi,
You said base64_encrypt(), but didn’t you mean base64_encode() ?

As you are probably aware, base64 is NOT encryption, it’s just encoding so that you can transfer things around that would normally not be transferable (e.g. ascii characters that don’t agree with most browsers, or the HTTP spec such as new lines or binary data within the URL etc.).

My solution to this was to use the mcrypt extension, and pass actually encrypted parameters over so there is no risk of tampering (just as you wanted), but my main use for this is a lot less sensitive - an email form that I can pass any e-mail address to and not worry about abuse.

Take a look at the following example:


// I'm paranoid OK!
$crypt_key = "oru-9(£20fjasdiofewfqwfh;klncsahei223gfpaoeighew";

	//Encrypt Function
	function doEncrypt($encrypt)
	{
		global $crypt_key;
		
		$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND);
		$passcrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $crypt_key, $encrypt, MCRYPT_MODE_ECB, $iv);
		$encode = base64_encode($passcrypt);
		
		return $encode;
	}

	//Decrypt Function
	function doDecrypt($decrypt)
	{
		global $crypt_key;
		
		$decoded = base64_decode($decrypt);
		$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND);
		$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $crypt_key, $decoded, MCRYPT_MODE_ECB, $iv);
		
		return str_replace("\\0", '', $decrypted);
	}

This is using the Rijndael 256 bit blockcipher fpr encryption and decryption… which is fairly secure, but you could choose twofish, trippledes, blowfish… or any other algorithm you feel is suitable and is supported by the mcrypt library.

You could then use it as follows on the page that creates the encrypted link


$l_secure_query = 'var1=abc&user=whoever&amount=19.42';
$l_encrypted = doEncrypt($l_secure_query);
print ('<a href="whatever.php?' . $l_encrypted . '">Pay Now</a>');

And use this on the page that needs to decrypt the arguments passed


if ( ! strlen($_SERVER['QUERY_STRING']) )
{
  exit ();
}

$l_secure_query = null;
parse_str ($_SERVER['QUERY_STRING'], $l_secure_query);

print ('You are going to pay: $' . $l_secure_query['amount']);

One thing you have to keep track of is the length of the encrypted data you’re passing around pages… if it gets too big (which it easily can) then some browsers will just bork.

Regards,

  • Harry :slight_smile:

I think it is something to do with the line:

 $l_encrypted = doEncrypt($l_secure_query);  

because the page is processed when this is commented out, but when un-commented, the page ceases to provide.

Make sure you have error reporting turned on, and that the mcrypt extension is enabled.

To check if the mcrypt extension is installed please check the phpinfo() output or run the command ‘php -m’.

nothing is mentioned in phpinfo, does this mean mcrypt isn’t active?

To enable the mcrypt extension you have to add (or uncomment) an extension line in the servers php.ini (and restart your webserver depending on it’s configuration).

On Windows it would look like the following:


extension = php_mcrypt.dll

On Unix/Other it would look like:


extension = mcrypt.so

If mcrypt is mentioned nowhere in the PHP module information - then that generally means it’s not enabled.

Any other ways around it because we don’t have access to the files, as we host the site with a external company.

You can use session variables to provide hidden storage (relatively secure), although it requires a little more planning.

Ideally you shouldn’t have to be passing sensitive items through the client, and you should have enough checking in each script to make sure that there is no possible way to mix up.

For example, on one page you would set $_SESSION[‘user.id’] to the users primary key. Then on pay.php it would retrieve all items that need paying from the database and display them to the user and link to payitem.php (or whatever) which would be passed the items primary key. On payitem.php you would make sure that the item that the user is trying to pay is actually owned by the user etc. etc.

The general rule is that you should be implementing security early on in the design stage, rather than patching holes further down the line.

Regards,

  • Harry :slight_smile:

Ok, well thanks. I may change the design to work from session, i’m already using sessions to a degree, but had to use URL parameters in a few instances because I couldn’t figure a way around it. ‘It,’ being a way of allowing a master login account to view and select child accounts.