I want to pass some variable to the URL using PHP $_GET['']; for example:
I have a form on a landing page with five input fields: Name, Surname, Email, Confirm-Email, Phone I pick these variables up now I want to add these to a Base URL so that they can be picked up by another web page.
My question is how safe is this and what is the best method to protect these variables or perhaps make them invisible under the new url...?
I could use php curl() or sockets but the server where I want to send the data to does not allow me to so thats why I want to use $_GET['']'
You should not use $_GET if you want to make your data secure.
There is no option using which you can make $_GET secure or invisible.
You should use $_POST for sending data to other url if you do not want to make your data visible and secure.
Even your data is not stored by browser when you use post method and it is more difficult to hack.
It's unsafe, as URI parameters can be edited by anyone and anything. Best method to "protect" those is to encrypt them when sending (which means the recipient must be able to decrypt them) combined with a checksum to make sure none of the parameters were altered. Another type of protection is not using HTTP but using HTTPS instead, of course.
Both GET and POST is unsafe if you're not using HTTPS.
So if you have to use GET to submit your form, a verify token is suggeseted. Like OAuth, server will return the data through GET, but there's a access_token to protect data.
Encode your variables first, then decode it on the other server. this way no one can easily revert it. Make sure to change var $skey = "SecretKey0001"; to something else.
<?php
class Encryption {
var $skey = "SecretKey0001"; // you can change it
public function safe_b64encode($string) {
$data = base64_encode($string);
$data = str_replace(array('+','/','='),array('-','_',''),$data);
return $data;
}
public function safe_b64decode($string) {
$data = str_replace(array('-','_'),array('+','/'),$string);
$mod4 = strlen($data) % 4;
if ($mod4) {
$data .= substr('====', $mod4);
}
return base64_decode($data);
}
public function encode($value){
if(!$value){return false;}
$text = $value;
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->skey, $text, MCRYPT_MODE_ECB, $iv);
return trim($this->safe_b64encode($crypttext));
}
public function decode($value){
if(!$value){return false;}
$crypttext = $this->safe_b64decode($value);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$decrypttext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->skey, $crypttext, MCRYPT_MODE_ECB, $iv);
return trim($decrypttext);
}
}
$data_array['Name'] = 'Name';
$data_array['Surname'] = 'Surname';
$data_array['Email'] = 'Email';
$data_array['Confirm-Email'] = 'Confirm-Email';
$data_array['Phone'] = 'Phone';
$data_json = json_encode($data_array);
$encrypt = new Encryption;
$encoded_vars = $encrypt->encode($data_json);
$BASE_URL = 'http://example.com?data=' . $encoded_vars;
echo $BASE_URL;
echo "<br>";
// reverse
$decrypt = new Encryption;
echo $decoded_vars = $decrypt->decode($encoded_vars);
echo "<br>";
$data = json_decode(urldecode($decoded_vars), true);
echo "<br>";
print_r($data);
?>
DEMO: http://sandbox.onlinephpfunctions.com/code/ef1acdcad0272d5d99e21b07183a479f564ac64c
Related
I've looked elsewhere at the same error but not found anyone having the same problem as me.
I am submitting a form from contactEdit.hbs (Handlebars) which is injected into the contact.php page, the form then POSTS to addcontact.php.
(contact.php [INJECT]=> contactEdit.hbs [POST]=> addcontact.php)
addcontact.php uses mcrypt, shown below.
define('IV_SIZE', mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC));
function encrypt ($key, $payload) {
$iv = mcrypt_create_iv(IV_SIZE, MCRYPT_DEV_URANDOM);
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $payload, MCRYPT_MODE_CBC, $iv);
$combo = $iv . $crypt;
$garble = base64_encode($iv . $crypt);
return $garble;
}
function decrypt ($key, $garble) {
$combo = base64_decode($garble);
$iv = substr($combo, 0, IV_SIZE);
$crypt = substr($combo, IV_SIZE, strlen($combo));
$payload = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $crypt, MCRYPT_MODE_CBC, $iv);
return $payload;
}
$key = "mysupersafeandsecretkeythatialmostforgottoremovewhenpostingthis";
After this, I encrypt the data submitted from the form on the previous page (contactEdit.hbs) and store the values in my database, example of the encryption below
// ENCRYPTION
if(!empty($nationality)){
$nationality = encrypt($key, $nationality);
}
if(!empty($landline)){
$landline = encrypt($key, $landline);
}
if(!empty($mobile)){
$mobile = encrypt($key, $mobile);
}
if(!empty($email)){
$email = encrypt($key, $email);
}
if(!empty($nationalid)){
$nationalid = encrypt($key, $nationalid);
}
if(!empty($passport)){
$passport = encrypt($key, $passport);
}
if(!empty($dob)){
$dob = encrypt($key, $dob);
}
When ALL of the input boxes are filled out on the form and submitted, it works perfectly... Everything is posted to the database and we are returned to the contacts.php page by a simple header redirect at the end of the script (I also store the values in a .json array, which works fine!)
NOW here's the problem. When only a couple (or none) of the input boxes are filled out and we try to submit the form, I receive the following error:
mcrypt_decrypt(): The IV parameter must be as long as the blocksize in addcontact.php on line 23
Here's line 23:
$payload = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $crypt, MCRYPT_MODE_CBC, $iv);
If anything was filled out on the form, it is still encrypted and posted to the database successfully, along with being saved to the .json file still.
So why do I get this error, everything still seems to work fine? The only problem is that as a result of this error, addcontact.php will not execute the header redirect (header('Location: contacts.php');) at the end of the script, this comes with its own error:
: Cannot modify header information - headers already sent by (output started at addcontact.php:23) in addcontact.php on line 193
Help appreciated, if I've not been clear enough then feel free to ask :-)
For security purpose I don't want that my users can read a url to access to a picture for example.
Actually I have
https://files.domain.com/TERFD/TES/photos/20150729-0961577ba8bc6c31e7339acf0c53969a170609038345c3a0602d646a48067c10-ANnKb.jpeg?uid=3&token=360d641dc692041cbea673a
But I prefer that the user can read the picture's path or the token
So that, I wrote the following functions :
public function encrypt($data) {
$key = "df456gfd";
$data = serialize($data);
$td = mcrypt_module_open(MCRYPT_DES,"",MCRYPT_MODE_ECB,"");
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td,$key,$iv);
$data = base64_encode(mcrypt_generic($td, '!'.$data));
mcrypt_generic_deinit($td);
return $data;
}
public function decrypt($data) {
$key = "df456gfd";
$td = mcrypt_module_open(MCRYPT_DES,"",MCRYPT_MODE_ECB,"");
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td,$key,$iv);
$data = mdecrypt_generic($td, base64_decode($data));
mcrypt_generic_deinit($td);
if (substr($data,0,1) != '!')
return false;
$data = substr($data,1,strlen($data)-1);
return unserialize($data);
}
My URL is now:
https://files.domain.com/NcGDHiMnmM3fYW2W03ulyJdlCp6FaXCYDlxzWe74zH63+YpfUSPuKnxWIG1C1WNNjw/jU7coduYchvf44Lh4yiVdcL7uyx4vA4oOj14keiohQ9geIYVxsa4n07E0TXbstSETbhqGejE03Ai5hGcJEa7U/aA7z1fRkQEAxepH9j6yu+tQZESp3dXg7JUvVffI9lbpPtbGLj8=
I can decrypt it from files.domain.com and return the requested file.
Is it a good practice ?
Thx
You're actually just slowing down your application with this practice. Honestly, you're making it too complex. Why not use something like base64_encode() and base64_decode(). These functions are actually faster than your decryption and encryption functions.
I'm using PHP and CI framework, I want to send variable through URL but I want it to be somewhat encrypted.
For example i want to send variable named id:
www.trythis.com/site?id=123
I want it to be
www.trythis.com/site?id=VkxSiOW31S
The encrypted text is just an example.
How can I do that? or is there CI function that can do this?
Note: I already try base64_encode but it somehow can't be used in CI due to its special characters such as ==.
CodeIgniter has Encryption Class. You can use that class to encrypt and decrypt. To configure follow the steps
Setting your Key
$config['encryption_key'] = "YOUR KEY";
Initializing the Class
$this->load->library('encrypt');
To encode use
$id = '123';
$encrypted_id = $this->encrypt->encode($id);
//$url = 'www.trythis.com/site?id=' . $encrypted_id;
And to decode
//$encrypted_id = $_GET['id'];
$decrypted_id = $this->encrypt->decode($encrypted_id);
I made this class for the same purpose:
class Cypher
{
public $encrypted;
public $decrypted;
public function __construct($_value) {
$this->encrypted = $this->encrypting($_value);
$this->decrypted = $this->decrypting($_value);
}
private function encrypting($_value) {
$key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$utf8 = utf8_encode($_value);
$cipher = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $utf8, MCRYPT_MODE_CBC, $iv);
$cipher = $iv.$cipher;
$base64 = base64_encode($_value);
return $base64;
}
private function decrypting($_value) {
return base64_decode($_value);
}
}
Let's try your example:
$cypher = new Cypher('123');
header("location: www.trythis.com/site?id=".$cypher -> encrypted);
On www.trythis.com/site page:
$id = isset($_GET['id']) ? new Cypher($_GET['id']) : "";
echo $id -> decrypted;
I found out that I should not use global variables like global $auth_key for sensitive data's (Correct me if that's not true.) so I wanted to use defined variables for storing security keys.
Inside config.php salt keys are defined.
define('AUTH_KEY','::~K~UC*[tlu4Eq/]Lm|h');
define('SECURE_AUTH_KEY', 'QsTMvbV+tuU{K26!]J2');
In encryption.php contains the encryption functions where AUTH_KEY and SECURE_AUTH_KEY will be used inside.
function encrypt_text($value) {
if(!$value) return false;
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, **AUTH_KEY_HERE**, $value, MCRYPT_MODE_ECB, **SECURE_AUTH_KEY_HERE**);
return trim(base64_encode($crypttext));
}
function decrypt_text($value) {
if(!$value) return false;
$crypttext = base64_decode($value);
$decrypttext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, **AUTH_KEY_HERE**, $crypttext, MCRYPT_MODE_ECB, **SECURE_AUTH_KEY_HERE**);
return trim($decrypttext);
}
Is there a way to do that? or any other solutions you can recommend? Please note that these keys are real important for encryption of sensitive informations.
Also, a another question, what is the maximum length of keys to be used on mcrypt?
Thank you and looking forward for reply of yours.
as a rule: the logner the key, the stonger the encryption. Secondly, don't use ECB unless your data is very short, you ought to use CBC or something stronger. Third: use a salt or initialization vector. Lastly read this: https://www.owasp.org/index.php/Cryptographic_Storage_Cheat_Sheet
Using a constant is just like using a variable except there is no dollar sign.
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, AUTH_KEY, $value, MCRYPT_MODE_ECB, SECURE_AUTH);
There is nothing inherently more secure in this approach over using the global key word. Though this approach is preferred. By using a constant you are saying this is a static value I will use across the application. Having to use global on the other hand is often just a result of bad design or laziness. It leads to code that is hard to follow, abusing what scoping tries to accomplish.
Key length is dependent on the encryption algorithm used. RTM.
Yes you can use the define variable like you are doing, see the example
define('AUTH_KEY','::~K~UC*[tlu4Eq/]Lm|h');
function abc()
{
echo AUTH_KEY;
}
abc(); // ::~K~UC*[tlu4Eq/]Lm|h
http://codepad.viper-7.com/tUAg6D
Although choosing constants would be preferable over plain variables, this kind of information is better stored inside a configuration file rather than your code.
Also, for better reuse and avoid having those global values lying around it would be a better idea to encapsulate the functionality:
class MyCrypto
{
private $key;
private $cipher;
private $mode;
public function __construct($key, $cipher, $mode = "cbc")
{
$this->key = $key;
$this->cipher = $cipher;
$this->mode = $mode;
}
public function generate_salt()
{
return mcrypt_create_iv(
mcrypt_get_iv_size($this->cipher, $this->mode),
MCRYPT_DEV_URANDOM
);
}
public function encrypt($data) { ... }
public function decrypt($data) { ... }
}
I've added a salt generator function to be used for every encryption operation;
Lastly, I would recommend using CBC mode - MCRYPT_MODE_CBC.
Update (27/09/17):
Since mcrypt_encrypt is DEPRECATED as of PHP 7.1.0. Ive added a simple encrypt/decrypt using openssl.
function encrypt($string, $key = 'PrivateKey', $secret = 'SecretKey', $method = 'AES-256-CBC') {
// hash
$key = hash('sha256', $key);
// create iv - encrypt method AES-256-CBC expects 16 bytes
$iv = substr(hash('sha256', $secret), 0, 16);
// encrypt
$output = openssl_encrypt($string, $method, $key, 0, $iv);
// encode
return base64_encode($output);
}
function decrypt($string, $key = 'PrivateKey', $secret = 'SecretKey', $method = 'AES-256-CBC') {
// hash
$key = hash('sha256', $key);
// create iv - encrypt method AES-256-CBC expects 16 bytes
$iv = substr(hash('sha256', $secret), 0, 16);
// decode
$string = base64_decode($string);
// decrypt
return openssl_decrypt($string, $method, $key, 0, $iv);
}
$str = 'Encrypt this text';
echo "Plain: " .$str. "\n";
// encrypt
$encrypted_str = encrypt($str);
echo "Encrypted: " .$encrypted_str. "\n";
// decrypt
$decrypted_str = decrypt($encrypted_str);
echo "Decrypted: " .$decrypted_str. "\n";
In your example, you are using the same initialization vector **SECURE_AUTH_KEY_HERE** when you can allow PHP to create the iv for you this way you only need 1 SECURE_KEY defined.
<?php
define('SECURE_KEY',md5('your secret key'));
/**
* Encrypt a value
*/
function encrypt($str){
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
return mcrypt_encrypt(MCRYPT_RIJNDAEL_256, SECURE_KEY, $str, MCRYPT_MODE_ECB, $iv);
}
/**
* Decrypt a value
*/
function decrypt($str){
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, SECURE_KEY, $str, MCRYPT_MODE_ECB, $iv));
}
//32
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
//Create an initialization vector (IV) from a random source
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
echo decrypt(encrypt('Encrypt me'));
?>
UPDATE (SOLUTION)
Since this post seems to get decent amount of attention, I'd like to let you know that the solution ended up being to provide a proper enctype (content type) parameter in the <FORM> declaration. You must set the value to multipart/form-data to prevent encoding that would otherwise take place using the default enctype of application/x-www-form-urlencoded. A small excerpt below from Forms in HTML Documents at w3.org:
The content type
"application/x-www-form-urlencoded" is
inefficient for sending large
quantities of binary data or text
containing non-ASCII characters. The
content type "multipart/form-data"
should be used for submitting forms
that contain files, non-ASCII data,
and binary data.
And here is the proper FORM declaration:
<FORM method="POST" action="/path/to/file/" name="encryptedForm" enctype="multipart/form-data">
INITIAL QUESTION
I am working on a form spam protection class which essentially replaces form field names with an encrypted value using mcrypt. The problem with this is that mcrypt encryption is not limited to only alphanumeric characters which would invalidate form fields. Given the code below, can you think of any reason why I'd be having problems decrypting the values of the already encrypted array?
/**
* Two way encryption function to encrypt/decrypt keys with
* the DES encryption algorithm.
*/
public static function encryption($text, $encrypt = true)
{
$encrypted_data = '';
$td = mcrypt_module_open('des', '', 'ecb', '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
if (mcrypt_generic_init($td, substr(self::$randomizer, 16, 8), $iv) != -1) {
if ($encrypt) {
// attempt to sanitize encryption for use as a form element name
$encrypted_data = mcrypt_generic($td, $text);
$encrypted_data = base64_encode($encrypted_data);
$encrypted_data = 'i' . strtr($encrypted_data, '+/=', '-_.');
self::$encrypted[] = $encrypted_data;
} else {
// reverse form element name sanitization and decrypt
$text = substr($text, 1);
$text = strtr($text, '-_.', '+/=');
$text = base64_decode($text);
$encrypted_data = mdecrypt_generic($td, $text);
}
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
}
return $encrypted_data;
}
I later make a call setting a hidden form element's value using:
base64_encode(serialize(self::$encrypted))
Essentially the hidden field contains an array of all form fields which were encrypted with their encrypted value. This is so I know which fields need to be decrypted on the backend. Upon form submission this field gets parsed on the backend with the following code:
// load the mapping entry
$encrypted_fields = $input->post('encrypted', '');
if (empty($encrypted_fields)) {
throw new AppException('The encrypted form field was empty.');
}
// decompress array of encrypted fields
$encrypted_fields = #unserialize(base64_decode($encrypted_fields));
if ($encrypted_fields === false) {
throw new AppException('The encrypted form field was not valid.');
}
// get the mapping of encrypted keys to key
$data = array();
foreach ($_POST as $key => $val) {
// if the key is encrypted, add to data array decrypted
if (in_array($key, $encrypted_fields)) {
$decrypted = self::encryption($key, false);
$data[$decrypted] = $val;
unset($_POST[$key]);
} else {
$data[$key] = $val;
}
}
// merge $_POST array with decrypted key array
$_POST += $data;
My attempts to decrypt the encrypted form field keys are failing. It's simply creating a new garbled key in the $_POST array. My guess is that either base64_encoding or serialization is stripping chars from the $encrypted_data. Could somebody verify if this is the culprit and whether there are any alternative methods for encoding form keys?
So I took your code, and modified it a little so that I can remove the element of a post request and your function seems to work fine. If you take the code I posted and create a script with it, it should run in the cli and you'll see its encrypting/decrypting the fields correctly. This would have to mean that the post request is some how garbling the encrypted/serialized/encoded data. If using a framework, I would look more into how it handles the post array as it could altering your keys/values causing them to not match up. The code that you posted seems fine.
<?php
/**
* Two way encryption function to encrypt/decrypt keys with
* the DES encryption algorithm.
*/
function encryption($text, $encrypt = true, &$encryptedFields = array())
{
$encrypted_data = '';
$td = mcrypt_module_open('des', '', 'ecb', '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
if (mcrypt_generic_init($td, substr('sdf234d45)()*5gf512/?>:LPIJ*&U%&^%NBVFYUT^5hfhgvkjtIUUYRYT', 16, 8), $iv) != -1) {
if ($encrypt) {
// attempt to sanitize encryption for use as a form element name
$encrypted_data = mcrypt_generic($td, $text);
$encrypted_data = base64_encode($encrypted_data);
$encrypted_data = 'i' . strtr($encrypted_data, '+/=', '-_.');
//self::$encrypted[] = $encrypted_data;
$encryptedFields[] = $encrypted_data;
} else {
// reverse form element name sanitization and decrypt
$text = substr($text, 1);
$text = strtr($text, '-_.', '+/=');
$text = base64_decode($text);
$encrypted_data = mdecrypt_generic($td, $text);
}
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
}
return $encrypted_data;
}
$encryptedFields = array();
// encrypt some form fields
encryption('firstname', true, $encryptedFields);
encryption('lastname', true, $encryptedFields);
encryption('email_fields', true, $encryptedFields);
echo "Encrypted field names:\n";
print_r($encryptedFields);
// create a usable string of the encrypted form fields
$hiddenFieldStr = base64_encode(serialize($encryptedFields));
echo "\n\nFull string for hidden field: \n";
echo $hiddenFieldStr . "\n\n";
$encPostFields = unserialize(base64_decode($hiddenFieldStr));
echo "\n\nDecrypted field names:\n";
foreach($encPostFields as $field)
{
echo encryption($field, false)."\n";
}
?>