Jump to content

Need to Validate Hidden Form Values??


doubledee

Recommended Posts

At the top of my script I have...

	$sessMemberID = (isset($_SESSION['sessMemberID']) ? $_SESSION['sessMemberID'] : '');

 

 

Then down in my Form I have...

		<!-- RequestorID -->
<input id="requestorID" name="requestorID" type="hidden" value="<?php echo $sessMemberID; ?>" />

 

 

When the Form is submitted, do I need to check the value of $sessMemberID before processing my Form??

 

 

Debbie

 

Link to comment
Share on other sites

There isn't even any need to use a hidden form field for that. If you already have the value in a $_SESSION var, why would you need to send it via a form?

 

You're right, I really don't.

 

Guess I just got caught up in the flow...

	<!-- RequestorID -->
	<input id="requestorID" name="requestorID" type="hidden" value="<?php echo $sessMemberID; ?>" />

	<!-- RequesteeID -->
	<input id="requesteeID" name="requesteeID" type="hidden" value="<?php echo $memberID; ?>" />

	<!-- Submit Form -->
	<input type="submit" name="submit" class="button" value="Yes"/>
	<input type="submit" name="submit" class="button" value="No"/>

 

 

But just for argument's sake, would I need to Check/Re-Check the value from the UN-Submitted for to the Submitted Form??

 

I always wonder how *crazy* you need to get with Data Validation?!  I mean once something is validated, can't it be assumed to remain that way? 

 

Like my $sessMemberID = $_SESSION['memberID'];

 

You could argue that I need to check that against the database or something and go through a long extensive line of data checking everytime I go from page to page, right?

 

Where do you draw the line?!  :-/

 

 

Debbie

 

 

Link to comment
Share on other sites

All form data can be tampered with, therefore it all needs to be validated anytime a form is submitted.

 

So how would you recommend I improve the code I posted above??

 

I know the $sessMemberID from my Session so I guess that is safe after the Form is submitted, but what about $memberID??

 

Maybe some background would help...

 

The current logged in User is looking at someone's Member Profile (e.g. DoubleDee is looking at SuzyQ's).

 

DoubleDee clicks on a link "Request Friendship" and is taken to...

 

http://local.debbie/account/request_friend.php?user=SuzyQ

 

From there, I grab the $_GET['user'] and do a whole series of checks...

 

- Query String exists?

- Username valid Format?

- Username in database?

- Username equates to which MemberID

 

Now that I have the MemberID, when the current User submits the "Friend-Request" Form with a "Yes" or "No", I need to pass the $sessMemberID (i.e. Requestor) and $memberID (i.e. Requestee) to the part of my script that processes the Request and ultimately updates the "Friend" table.

 

I thought what I was doing was pretty innocuous...  :shrug:

 

I could make sure the memberID is an Integer.  That is easy.

 

But do I have to go back and look it up in the database?

 

And even if I did, what would I compare it against?  (Once the Form is submitted, I lose the username from the original Query String?!

 

Please don't tell me this is going to require another 200 lines of code and lots of headaches!!

 

 

Debbie

 

 

Link to comment
Share on other sites

But do I have to go back and look it up in the database?

 

Yes.

 

But I have no way of knowing what to check for.

 

It's circular logic?!

 

If I load the "request_friend.php" script with the person I want to Friend in the URL, then that is a known item.

 

But after I do all this checking to make sure what was in the $_GET was okay, and then I submit the Form, the Submitted Form has no history to know if "user=SuzyQ" or "memberID=123" is what we are checking for, because the Forms are "stateless"?!  :shrug:

 

Normally when I submit a Form, my PHP validates the data like "Is this a valid Name?", "Is this a valid Email format", and so on.

 

But I have no way of knowing in the Submitted Form that DOubleDee wanted to send a Friend-Request to "SuzyQ"...

 

See what I mean?!

 

 

Debbie

Link to comment
Share on other sites

But it doesn't matter. All you need to check is that the user has permission to send the message to the user that was sent with the form.

 

Barring CSRF attacks, the user would have to tamper with the form themselves. If they already have permission to send the message to the person they tampered the form to send it to, then what difference does it make? You are simply making sure they can't tamper with the form to send a message to someone that they can't normally send one to.

Link to comment
Share on other sites

But it doesn't matter. All you need to check is that the user has permission to send the message to the user that was sent with the form.

 

Barring CSRF attacks, the user would have to tamper with the form themselves. If they already have permission to send the message to the person they tampered the form to send it to, then what difference does it make? You are simply making sure they can't tamper with the form to send a message to someone that they can't normally send one to.

 

I'm sorry, but you are losing me here.

 

Let's say Member #1 goes into her account and starts browsing Profiles.  She remembers talking to Member #2 and figures it would be nice if they were "Friends".  So Member #1 goes into Member #2's public Profile and clicks on the link "Make a Friend-Request" which takes Member #1 to...

 

/account/request_friend.php?user=Member2

 

 

At the top of "request_friend.php", I have this code...

$sessMemberID = (isset($_SESSION['sessMemberID']) ? $_SESSION['sessMemberID'] : '');

 

 

Initially, the Form in this script is not submitted, so this branch of my code fires...

}else{
	// Form was not Submitted (Get).

	// ******************
	// Check Username.	*
	// ******************
	if (isset($_GET['user']) && $_GET['user']){
		// Username found in URL.


		// ************************
		// Check Username Format.	*
		// ************************
		if (preg_match('~(?x)			# Comments Mode
					^			# Beginning of String Anchor
					(?=.{8,30}$)	# Ensure Length is 8-30 Characters
					[a-z0-9_.-]*	# Match only certain Characters
					$			# End of String Anchor
					~i', $_GET['user'])){
			// Valid Username Format.


			// ************************
			// Check Username Exists.	*
			// ************************

			// Build query.
			$q2 = "SELECT id
							FROM member
							WHERE username=?";

			// Prepare statement.
			$stmt2 = mysqli_prepare($dbc, $q2);

			// Bind variable to query.
			mysqli_stmt_bind_param($stmt2, 's', $_GET['user']);

			// Execute query.
			mysqli_stmt_execute($stmt2);

			// Store results.
			mysqli_stmt_store_result($stmt2);

			// Check # of Records Returned.
			if (mysqli_stmt_num_rows($stmt2)==1){
				// Username Found.

				// Bind result-set to variable.
				mysqli_stmt_bind_result($stmt2, $memberID);

				// Fetch record.
				mysqli_stmt_fetch($stmt2);

				// Set Username.
				$user = $_GET['user'];

				// Set Session for Messaging.
				$_SESSION['username'] = $user;

 

 

At this point the Requestor's (i.e. Member #1) ID is stored in $_SESSION['sessMemberID']

 

And the Requestee's (i.e. Member #@) ID is stored in the local variable "memberID" which obviously does not persist when the Form is submitted.

 

In order to make a new Friend Request or Update the existing Friend-Request record in the database, I need:

 

- sessMemberID

- memberID

- requestor_approved

- requestee_approved

 

 

When the Form is submitted I lose $memberID unless I store it as a hidden field in the Form and it gets brought over in the global variable, $_POST, or I stash it in the $_SESSION variable.

 

You are saying that if it is submitted in $_POST then I need to validate it, and I am saying I don;t understand how.

 

Can you please help me understand how to do this?

 

Also, if I stashed it in the Session like this...

			// Check # of Records Returned.
			if (mysqli_stmt_num_rows($stmt2)==1){
				// Username Found.

				// Bind result-set to variable.
				mysqli_stmt_bind_result($stmt2, $memberID);

				// Fetch record.
				mysqli_stmt_fetch($stmt2);

				// Set Username.
				$user = $_GET['user'];

				// Set Session for Messaging.
				$_SESSION['username'] = $user;

//====> LOOK BELOW
				// Set memberID for Form Processing.
				$_SESSION['memberID'] = $memberID;

 

...then would that satisfy your security concerns?

 

I don't mean to be a pest, but I just was not following you, and I want to get this down right!!  8)

 

Thanks,

 

 

Debbie

 

 

Link to comment
Share on other sites

Initially I thought this was for private messages, but now I see it is for friend requests. Is there any sort of restrictions on what users any other user can add as a friend, or can any user add any user as a friend?

 

If there is no restrictions, all you need to do is make sure that the requested user exists and that they are not already friends.

 

If there is restrictions, you can validate that accordingly.

 

Either way, you know the requested member ID - that's all you care about. It is irrelevant if the member ID is different than it was when you originally displayed the form, because your code will handle it the same way. Like I said, the user would have to purposefully and manually tamper with the form data in order for that ID to change.

 

Whether or not you end up with the same member ID after submitting the form as you did when the form was displayed makes no difference.

Link to comment
Share on other sites

I personally think you're going about this in a very... barbaric way.  Foremost, if you're running your scripts off of query strings, you've destroyed all need for 'pretty URLs', and IMO you're causing yourself more headache than it's worth putting the user's name in the query string.  You're exposing the scripting method and making it easy to tamper with - which is why you're needing to run the name through regex.  Like many have said above me, you're making it more difficult on yourself than you need to.

 

You definitely do not need that hidden form input.  What happens when the session is timed-out but the page is never left, leaving the form data with the old data?

 

You have the script 'request_friend', which I imagine does only one thing, so why even bother with GET?  It suggests to me that you're on your own account page and having to manually input  into a form input a user's name to make a friend contact.  This is not the best practice as you're opening yourself up to a headache.  Never trust your users.

 

Personally, you need to rethink your entire methodology here.  Your users should be presented with the option to add a user as their friend from the OTHER person's profile.  Here's my approach:

 

From profile/User OR profile.php?u=User

[*] Retrieve user from profile URI

[*] Check relation table against profile user_id and session user_id

[*] If relation exists, set a value to TRUE, else FALSE

<?php
    // Retrieve user profile
    $user = $get_user_method;

   // Check to see if profile is not owned by current user
    if( $_SESSION[user_id] != $user['user_id'] )
    {
         // Since the logged user is on another's profile, check to see if they are friends
         $relation = $get_relation_method( array( 'user_1' => $_SESSION[user_id], 'user_2' => $user[user_id] ) );

         // Check relation exists
         $related = ($relation ? TRUE : FALSE);
    }
?>

 

If the relationship exists, state so on the page, else, create a form / action div for javascript.

<?php
    if( $related ):
        echo 'You are friends with ' . $user[user_name];
    else:
        echo '<form><input type=hidden value=' . $user[user_id] . ' name=profile_id /><input type=button name=add_friend value=Add ' . $user[user_name] . ' as Friend />'
    endif;
?>

 

Now, from whatever action script will process this form, simply grab, validate, and actionize

<?php
    if( $_POST['add_friend'] )
    {
        // Check if both user IDs return valid users (using input value from form and session id)

        // Check if there's already a relation and error out accordingly

        // No relation exists, create it

        // Set page alerts for front-end fanciness to inform user the relation was created
    }
?>

Link to comment
Share on other sites

Initially I thought this was for private messages, but now I see it is for friend requests. Is there any sort of restrictions on what users any other user can add as a friend, or can any user add any user as a friend?

 

Any registered Member can request to be Friends with any other registered Member.

 

 

Going off topic for a second...

 

Is it a true statement, that if I store the $memberID in the $_SESSION that it is reasonable secure going from page to page?

 

 

Debbie

 

Link to comment
Share on other sites

Instead of telling me what you *think* I have done, and then going on and on about how to fix things, how about ask me first?  ::)

 

You've provided nearly nothing in terms of details.  I admit i missed the hidden for the other user, but the concepts of what I proposed are the same.  Regardless, your methodology needs improvement.  My suggestions provide info on how to successfully do what you're after.

 

If you encrypt the $_session id, and it checks out, then you can trust your data.

Link to comment
Share on other sites

Instead of telling me what you *think* I have done, and then going on and on about how to fix things, how about ask me first?  ::)

 

You've provided nearly nothing in terms of details.

 

I thought I was pretty detailed in Reply #4?!  :shrug:

 

I am more than willing to explain things in greater details if you helps you guys to help me out.  Just say so.

 

 

I admit i missed the hidden for the other user, but the concepts of what I proposed are the same.  Regardless, your methodology needs improvement.  My suggestions provide info on how to successfully do what you're after.

 

If you encrypt the $_session id, and it checks out, then you can trust your data.

 

Would you like me to explain my workflow again, since I can't post everything up here?

 

 

Debbie

 

 

Link to comment
Share on other sites

Is it a true statement, that if I store the $memberID in the $_SESSION that it is reasonable secure going from page to page?

 

Yes.    One issue with relying on $_SESSION values though is that they can break the ability for people to use multiple tabs when browsing your site.

 

As a bit of a contrived but completely possible example, lets say you have a page to view a user's friends list.  So say I go to one of my friends and star looking over their friends to see if there is anyone they have befriended that I might want to as well.  Next to each of the friends in that list you have a link/button that I can click to request to be friends.

 

Being the tab aficionado that I am I find a few people and for each one of them I 'Open in new tab' that add to friends list link.  Lets say I click the links for 'George', 'John', and 'Paul', in that order.  I'll have three tabs open then one for each of them with a form to put in a message or something and click add to finish and send the request.  Since the page for 'Paul' was the last one to be loaded though, his ID is going to be the one stored in the session.

 

So when I go to the tab showing 'George' and enter my message and hit send, your script will pull the ID out of $_SESSION but that ID will be for 'Paul' not 'George'.  As such 'Paul' will be getting my friend request with my message that was intended for 'George'.  The same would happen when I submit the page for 'John' and then finally for 'Paul'. 

 

/end of little example story.

 

That is why you should try and not use the session for such values.  You will want to pass them through the URL or hidden form fields.  As mentioned though, all form data can be tampered with so you always have to run your validation checks.  In the case of this member id value, as mentioned, there area really only a few things you need to check.

 

1) That it is a number

2) That the user represented by that number exists

3) That they are allowed to request to be friends with that user (since you said anyone can request anyone this check is basically an always-true check thus not really needed)

4) That they are not already friends with each other.

 

That's all.  Fairly simple check which you could probably do all in one query plus a (int) cast on the value.

 

Link to comment
Share on other sites

Kicken,

 

If you are telling me to avoid using $_SESSION all together, then you just broke a good part of all of my scripts, and at least several months worth of work...  :(

 

Not all together no, just for certain things.  Your current logged in user and their details can all go in $_SESSION without any issues.  Things that apply to the current user as a whole and are session-wide can go in there as well (ie, shopping cart data).

 

You just have to consider how storing information in the session might affect a person who is using multiple tabs.  For example I used to work on a system that users would do a search and "open" a student account then browse through other pages which pulled up details on that student (courses, grades, invoices, etc).  The way it worked is by storing that student id in the session and using it on each page.  This was all built back before tabbed browsing became popular so nobody really thought about it too much.

 

Fast-forward to current day where every modern browser has tabbed browsing and users take advantage of that fact, we had quite a few complaints about how if they tried to open a second student in a second tab it broke their first tab.  As of my last day there the issue had not been fixed yet.  It probably still hasn't due to how much of the system it affects that would need updated.

 

Link to comment
Share on other sites

In the case of this member id value, as mentioned, there area really only a few things you need to check.

 

1) That it is a number

2) That the user represented by that number exists

3) That they are allowed to request to be friends with that user (since you said anyone can request anyone this check is basically an always-true check thus not really needed)

4) That they are not already friends with each other.

 

That's all.  Fairly simple check which you could probably do all in one query plus a (int) cast on the value.

 

Okay, so here is what I added to my script...

 

(Instead of just looking for RequesteeID, I decided to see if the "Request" itself exists in the "Friend" table since that kills two-birds with one stone, right?!)

 

 

// *************************************************************
// HANDLE FORM.										 *
// *************************************************************
if ($_SERVER['REQUEST_METHOD']=='POST'){
	// Form was Submitted (Post).

	// Trim all Form Data.
	$trimmed = array_map('trim', $_POST);

	// Cast Form value.
	$trimmed['requesteeID'] = (int)$trimmed['requesteeID'];


	// ******************************
	// Check Friend-Request Exists.	*
	// ******************************

	// Build query.
	$q5 = "SELECT id
					FROM friend
					WHERE requestee=? AND requestor=?";

	// Prepare statement.
	$stmt5 = mysqli_prepare($dbc, $q5);

	// Bind variable to query.
	mysqli_stmt_bind_param($stmt5, 'ii', $trimmed['requesteeID'], $sessMemberID);

	// Execute query.
	mysqli_stmt_execute($stmt5);

	// Store results.
	mysqli_stmt_store_result($stmt5);

	// Check # of Records Returned.
	if (mysqli_stmt_num_rows($stmt5)==1){
		// Friend-Request Found.

		// Bind result-set to variable.
		mysqli_stmt_bind_result($stmt5, $requesteeID);

		// Fetch record.
		mysqli_stmt_fetch($stmt5);

	}else{
		// Friend-Request Not Found.
		$_SESSION['resultsCode'] = 'FRIEND_REQUEST_NOT_FOUND_2203';

		// Set Error Source.
		$_SESSION['errorPage'] = $_SERVER['SCRIPT_NAME'];

		// Redirect to Display Outcome.
		header("Location: " . BASE_URL . "/account/results.php");

		// End script.
		exit();
	}//End of CHECK REQUESTEE EXISTS

 

 

What do you think about that?

 

 

Debbie

 

 

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.