Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

PHP Encrypt URL 2

Status
Not open for further replies.

jasc2k

Programmer
Nov 2, 2005
113
GB
Hi All

Another task I am faced with on the development of my website project is somehow encypting my variables passed through the address bar. I have seen alot of disscussion on this topic also on goolge but managed to source the following:

Hashing sensitive data
Hashing algorithims provide a simple way to detect tampering. For instance, when passing an id variable from page to page as a user is browsing, the program may expect that this id stays constant. By computing and sending a hash of the data, each successive page can verify, with a high certanty, that the value of the id variable has not been altered:

$secret = 'MySecretWords';
$id = 12345;
$hash = md5($secret . $id);
After hashing the id value with the secret, we get a hash value. This will be passed, along with the id value, to the next page for processing:


In view_profile.php, we can detect tampering with the id value by re-hashing and comparing to the hash value from the previous page:

$secret = 'MySecretWords';
$id = $_REQUEST["id"]; //in this case the value is 12345
if (md5($secret . $id) == $_REQUEST["hash"]) {
//no tampering detected, proceed with other processing
} else {
//tampering of data detected
}
There is a disadvantage to using the hashing method discussed above; the value of id is visible to potentially malicious users. However, as long as the secret and the process for generating the hash (in this case, md5 is the hash algorithm, and the value hashed is the concatenation of $secret and $id) are unknown, malicious users will not be able to tamper with the id variable passed to the page.

Encrypting sensitive data
Next, we will discuss how we can use symmetric keys to protect sensitive data and at the same time do not reveal the actual data value.

The concept is very similar to hashing the value, but now instead we will use a symmetric key to encrypt and decrypt the data.




$key = “This encrypting key should be long and complex.”;
$encrypted_data = mcrypt_ecb (MCRYPT_3DES, $key, “12345”, MCRYPT_ENCRYPT); //encrypt using triple DES
$id = urlencode(base64_encode($encrypted_data));
The id will be base64 encoded and then urlencoded into Doj2VqhSe4k%3D so we will have the url as


(For perl programmer, you can use Digest::MD5 and Crypt::CBC to archive the same output)

To decrypt the information we received we will do the following:

$id = $_REQUEST["id"]);
$url_id = base64_decode(urldecode($id));

$decrypted_data = mcrypt_decrypt(MCRYPT_BLOWFISH,$key,$url_id, MCRYPT_MODE_CBC, $iv);
The idea here is to url decode the input id value and follow by base64_decode it and then use back the same algorithm to get the actual data, which is 12345 in this case.

This same idea can be used on session id to make sure the session id is not tampered with. One caveat to take note is encrypting and decrypting all data send and receive will possibly consume lot of cpu power, so make sure your system is properly size up.

Firstly if I have multiple variables ie ?id=blah&next=blah do I encypt EVERYTHING after id= or just the blah's? (If you can understand that, lol)

Secondly what I plan to do is to use a SESSION variable to hold the key to the decryption. If I were to pull this off would the HASHING method work? As I would no longer have to send the key via the address bar? Or should I still use the full encryption method using my SESSION variable - I cannot help but think this would cause alot of server strain but I guess its the most secure?

And again do I encrypt the variable names and their content or just their content?

Again tahsnk all for taking the time to read/comment on this post
 
Hi

jasc2k said:
do I encypt EVERYTHING after id= or just the blah's?
If you are encrypting only the blahs, PHP will populate $_GET and $_REQUEST correctly. If you are encrypting everything, then you will have to split up $_SERVER['QUERY_STRING'] yourself after decryption.

But personally I do not understand why you intend to do all this. For now it looks like a combination of bad coding practice and some healthy paranoia.


Feherke.
 
Hi there,
I am glad you replied to this topic as I trust your judgments. I will try and explain...

I basically have an index.php then include pages dynamically depending on the value of the id variable in the URL. I then went on to build a small messaging system for my users. When they reply to a message it will post the original msgid to my proccessing file using the URL however this is a bug as you could change that id and force a reply to another users message.

I did debate using $_POST in this but I could not get this to work correctly.

Another example would be where I wish to dynamically change the content on a page like I have a comments page that list the 50 last comments made but I also have a dropdown box where users can select 100 comments to display - again I use the address bar for this but dont want them to edit the URL to show millions!!

I hope this makes sense
Thanks
 
this is not a task for user generated data. you should not use either POST or GET for this.

instead you should hold the message thread ID in a session variable. then the only exposure you have is a man-in-the-middle attack on your session ID's.

if you need to provide the user with the ability to post to multiple messages from the same page then you may have to pass through the message ID. In which case you should authenticate server side whether THAT USER has authority to post to THAT MESSAGE.

bottom line: your application must never trust user submitted data. always authenticate (where necessary) and authorise before taking non-idempotent actions.

 
Hi

jasc2k said:
When they reply to a message it will post the original msgid to my proccessing file using the URL however this is a bug as you could change that id and force a reply to another users message.
Got it. That sounds as a good reason. Would be more elegant to check if the msgid is valid ( I mean, the message exists and its sender is the given recipient ), but the encryption looks like a more portable way as depends less from the data structure. However a partial check should still be done ( I mean, the message exists ). Ultimately it would depend on the used data structure if I would prefer to check or to encrypt.

Alternatively you could store the msgid in the session as $_SESSION['now_replying_to']=$msgid; when the reply [tt]form[/tt] is generated and get it from there when the reply is submitted. But personally I dislike it, because makes impossible to write multiple replies in the same time. ( I mean, in separate browser tabs or windows. )
jasc2k said:
I did debate using $_POST in this but I could not get this to work correctly.
Huh ? Wherever you send the msgid, it is exposed to the same risk of being altered.
jasc2k said:
dont want them to edit the URL to show millions
Personally I do not consider this a reason for encryption. Just check the received value and if is greater than 100, use a default just as it was not specified.


Feherke.
 
thanks guys for your replys

Great suggestion works a treat I did not even think of that!
Personally I do not consider this a reason for encryption. Just check the received value and if is greater than 100, use a default just as it was not specified.

I have removed the possibility of replying using the address bar - I am not even sure why I didnt do it this way first. But without both your comments I would not have looked at the actual design. I think my delete and unread functions are still susceptable to 'cheating' and I wonder if it would be too much to ask for someone to 'proof read' my code so far please? (I say too much beacuse its 500 lines) I do not feel its complicated code but maybe thats my problem?

I will also have to look at the SESSION variables more I had just assumed too many would clog up? lol!

Thanks again
 
Hi

jasc2k said:
I have removed the possibility of replying using the address bar
What do you mean, "replying using the address bar" ?

If that means you changed the [tt]form[/tt]'s [tt]method[/tt] from GET to POST, then I feel the need to repeat myself :
Feherke said:
Wherever you send the msgid, it is exposed to the same risk of being altered.
GET and POST are HTTP transfer methods so changing them only affects the way the data is transferred. But the data is primarily exposed to attacks due to the HTML. Anyway, there is no need to be a versed cracker, a regular user without technical knowledge will be able to edit the msgid with certain browser add-ons.

If I misunderstood your quoted words, just ignore me.

Feherke.
 
Hi,

I am not a very advanced PHP programmer but will try and explain anyway...

Basically before I could change the msgid in the URL to force my page to start a reply to a message of my choosing though I beleive now I do POST the variable so as you say it can still be cheated. I will have to check the message being replyed too as you suggested earleir to make sure its theirs.

But whereas before I was relying on the URL to know its a reply and not a new message it would change the form that got displayed on the page. Now I have added a variable to my function to handle this.

Below are two functions out of my message.php basically the function view will get called when a user displays a message, it will also display any replys to the message and below all that will display the reply form using the view function.

Code:
/**
 * This function will display the selected 
 * mail message and any replys.
 */
function view($msgid,$box) {
	global $session, $database;

	if($box == "inbox"){
		$result = $database->query("SELECT * FROM ".TBL_MAIL_INBOX." WHERE UserTo = '$session->username' AND mail_id = '$msgid'");
		$mail = mysql_fetch_array($result);
		$user = $mail['UserTo'];
		
		// here we will search for possible replys if its a primary message
		if($mail['re_id'] == 0){
			$resultx = $database->query("SELECT * FROM ".TBL_MAIL_SENT." WHERE UserFrom = '$session->username' AND re_id = '$msgid'");

			while($data = mysql_fetch_object($resultx)){
				$replys[] = array('UserFrom' => $data->UserFrom, 'UserTo' => $data->UserTo , 'Subject' => $data->Subject, 'Message' => $data->Message, 'mail_id' => $data->mail_id, 'SentDate' => $data->SentDate);
			 }
		}
		 
		markread($msgid, $box);
				
	} elseif($box == "sent") {
		$result = $database->query("SELECT * FROM ".TBL_MAIL_SENT." WHERE UserFrom = '$session->username' AND mail_id = '$msgid'");
		$mail = mysql_fetch_array($result);
		$user = $mail['UserFrom'];
	}
	
	if($user != $session->username) {
		echo "This is not your mail!";
	} else {
		if (count($mail)){
			echo "<table align='left' border='0' cellspacing='0' cellpadding='0'>";
			echo "<tr>";
					
			if ($box == "inbox"){
				echo "<td><img src='uploads/avatars/m_".$database->avatarShow($mail['UserFrom'])."' class='avatar_s' alt='User Image' /></td>";
				if(PROTECT){
					echo "<td>".$mail['UserFrom']."</td>";
				} else {
					echo "<td><a href='index.php?id=userinfo&amp;user=".$mail['UserFrom']."'>".$mail['UserFrom']."</a></td>";
				}
			} elseif ($box == "sent") { 
				echo "<td><img src='uploads/avatars/m_".$database->avatarShow($mail['UserTo'])."' class='avatar_s' alt='User Image' /></td>";
				if(PROTECT){
					echo "<td>".$mail['UserTo']."</td>";
				} else {
					echo "<td><a href='index.php?id=userinfo&amp;user=".$mail['UserTo']."'>".$mail['UserTo']."</a></td>";
				}
			}	
			echo "<td><b>".$mail['Subject']."</b><br />".$mail['Message'];
			echo "<br /><small>".$database->uk_date($mail['SentDate'])."</small></td>";
			
			echo "<td align='center'>";
			echo "<a href='index.php?id=mail&amp;action=showdelete&amp;box=".$box."&amp;msgid=".$mail['mail_id']."'>Delete</a></td>";

			if (count($replys)){
				foreach ($replys as $key => $reply){
					echo "<tr>";
								
					if ($box == "inbox"){
						echo "<td><img src='uploads/avatars/m_".$database->avatarShow($reply['UserFrom'])."' class='avatar_s' alt='User Image' /></td>";
						if(PROTECT){
							echo "<td>".$reply['UserFrom']."</td>";
						} else {
							echo "<td><a href='index.php?id=userinfo&amp;user=".$reply['UserFrom']."'>".$reply['UserFrom']."</a></td>";
						}
					} elseif ($box == "sent") { 
						echo "<td><img src='uploads/avatars/s_".$database->avatarShow($mail['UserTo'])."' class='avatar_s' alt='User Image' /></td>";
						if(PROTECT){
							echo "<td>".$mail['UserTo']."</td>";
						} else {
							echo "<td><a href='index.php?id=userinfo&amp;user=".$reply['UserTo']."'>".$reply['UserTo']."</a></td>";
						}
					}	
					echo "<td><b>".$reply['Subject']."</b><br />".$reply['Message'];
					echo "<br /><small>".$database->uk_date($reply['SentDate'])."</small></td>";
					
					echo "<td align='center'>";
					echo "<a href='index.php?id=mail&amp;action=showdelete&amp;box=".$box."&amp;msgid=".$reply['mail_id']."'>Delete</a></td>";
					echo "</tr>\n";
				}
			}
		
		echo "</tr>\n";
		echo "</table><br clear=all>";		
		
		} else {
			echo "<p>You have no messages!</p>";
		}
		
		if($box != "sent") {
			compose($mail['UserFrom'],$mail['mail_id'],$mail['Subject']);
		}
	}
}

	/**
 	* This function will display a form allowing
 	* user to create a new message.
 	*/
	function compose($to="",$msgid=0,$subject=""){
		global $form;
		if($to==""){
			$to = $_GET['to'];
		}
	?>

		<form id="compose" method="post" action="include/process.php">		  
		<fieldset>
			<legend><?php if($to){ echo "Message to: ".$to; } else { echo "Message:"; } ?></legend>
			<?php
				/**
				* If errors were found, display the total number of errors.
				* If errors occurred, they will be displayed.
				*/
				if($form->num_errors > 0){
				   echo "<h3>".$form->num_errors." error(s) found</h3>";
				}
			?>
			<dl>
			<?php if($msgid == "" || $to == ""){ ?>
				<dt><label for="mailTo">To:</label></dt>
				<dd><input type="text" name="to" id="to" class="text" size="23" maxlength="32" onkeyup="autoComplete();return false;" autocomplete="off" value="<?php if($to){ echo $to; } else { echo $form->value("to"); } ?>" /><?php echo $form->error("to"); ?>
				<br /><select id="matches" class="text_auto" multiple="multiple" style="display:none;" onclick="matchSelected(this);" ></select>
				</dd>
			
				<dt><label for="mailSubject">Subject:</label></dt>
				<dd><input type="text" name="subject" id="subject" class="text" size="23" maxlength="32" onfocus="hideField('matches')" value="<?php echo $form->value("subject"); ?>" /><?php echo $form->error("subject"); ?>
				</dd>
			<?php } else {
				echo "<dd><input type='hidden' name='to' value='".$to."' /></dd>";
				echo "<dd><input type='hidden' name='subject' value='RE: ".$subject."' /></dd>";
				echo "<dd><input type='hidden' name='id' value='".$msgid."' /></dd>";				
			} ?>	
				<dt><label for="body">Message:</label></dt>
				<dd><textarea name="body" id="body" class="textarea" rows="5" cols="33" onfocus="hideField('matches')"><?php echo $form->value("body"); ?></textarea><span style="vertical-align:top;"><?php echo $form->error("body"); ?></span>
				</dd>
				<dt><label>Styling:</label></dt>
				<dd>
				<input class="button_style" style="font-weight:bold;" type="button" value="B" onclick="applyTag(document.getElementById('body'), 'b')" />
				<input class="button_style" style="font-style:italic;" type="button" value="I" onclick="applyTag(document.getElementById('body'), 'i')" />
				<input class="button_style" style="text-decoration:underline;" type="button" value="U" onclick="applyTag(document.getElementById('body'), 'u')" />
				</dd>
			</dl>
		</fieldset>
		<fieldset class="action">
			<input type="hidden" name="subsendmail" value="1" />
			<input type="submit" name="process" id="process" class="button" value="Send" />
		</fieldset>
		</form>
		
	<?php
	}

Thanks again
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top