Voting cheaters who press BACK in the browser. Can I defeat?

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post by timvw »

If you set a constraint on your votes database so that the pair thing_you_vote_for, the_voters_id have to be unique you can leave out all the testing you do right now.

The way you do it right now, there is a chance that you run into concurrency problems.

For example, user opens 2 browsers, and surfs to the vote form.
browser1 votes
browser2 votes
browser1 -> code checks if vote has been submitted -> go on
browser2 -> code check if vote has been submitted -> go on
browser1 -> insert vote
browser2 -> problem

I know it seems very unlikely to happen, but as long as it's possible, it's just poor design imho. (So lookup about transactions and table locking)
User avatar
robster
Forum Contributor
Posts: 360
Joined: Wed Jul 16, 2003 8:28 am
Location: Sunshine Coast, Australia

Post by robster »

oooooh k :)

I THOUGHT I was all finished until I just read that last post :|

Not a worry, it's just more to do to make it more secure.
I'd like to thank everyone for their help, for as it is (without Transactions and Table Locking added yet) it is working.

Below is the code, complete and working (I have been testing it for a few hours now, will test some more before making it go live tomorrow). I want to add the Table Locking and Transactions stuff now it's been suggested also, but for now, here it is working. Pressing back in the browser, pressing refresh etc etc won't affect the database if there is already a vote. Big thanks to all, what an interesting process this has been for me :)

Code: Select all

<html>
<head>
<title>Voting Accepted - Redirecting</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta http-equiv="Cache-Control" Content="no-cache"> 
<meta http-equiv="Pragma" Content="no-cache"> 
<meta http-equiv="Expires" Content="0"> 
</head>

<body bgcolor="#666666">

<?
				require("config.php");
				
				$connection = mysql_connect($dbhost, $dbusername, $dbpassword);
				
				
				require_once ("forum/ipbsdk.php"); // Include SDK Functions and Files
				
				


					//============================================
					//  Get User POST data and assign to variables
					//============================================

					$Submit = trim(stripslashes($_POST['submit']));	
					$MemberId = trim(stripslashes($_POST['MemberId']));	
					$uid = trim(stripslashes($_POST['uid']));
					$entryid = trim(stripslashes($_POST['entryid']));	
					$year = trim(stripslashes($_POST['year']));	
					$month = trim(stripslashes($_POST['month']));	
					$choice = trim(stripslashes($_POST['Choose']));	



					//=======================================================================
					// Covert the $choice variable to something intelligible for the database
					//=======================================================================
					
					if ($choice == "1 - Poor")
					{
						$chosen = "1";
					}
					if ($choice == "2 - Better")
					{
						$chosen = "2";
					}
					if ($choice == "3 - Good")
					{
						$chosen = "3";
					}
					if ($choice == "4 - Very Good")
					{
						$chosen = "4";
					}
					if ($choice == "5 - Excellent")
					{
						$chosen = "5";
					}




					//========================================================================================
					// Let's check if the user is cheating by a refresh, we will see if they have voted as yet
					//========================================================================================


				//Is the user logged in?
				if (is_loggedin()) 
				{
		
					//Get the logged in users information
					$userinfoid = get_info(); 

					//now find out that users ID
					$member_id = $userinfoid['id']; 
		
		
					//Set x to 0 meaning we presume that memberid has not voted yet
					$x = "0";
		


					//========================
					// Check if user has voted
					//========================
					$votecontent = mysql_db_query($dbname, "SELECT * FROM votes ORDER BY id ASC");
					$Xvotecontent = mysql_fetch_array($votecontent);
					$Max = mysql_num_rows($votecontent);
					for ($loop=1; $loop<=$Max; $loop++)
					{ 
						$VotesEid = $Xvotecontent["eid"];
						$VotesUid = $Xvotecontent["uid"];
						$Votesrating = $Xvotecontent["rating"];
						$VotesMonth = $Xvotecontent["month"];
						$VotesYear = $Xvotecontent["year"];
						
						
						if ($VotesUid == $member_id) //If logged in user HAS voted (works)
							{
							//$printer2 = "x member on $x";
							if ($year == $VotesYear) //If user voted in the same year (works)
								{
								//$printer2 = "x year on $x";
								if ($month == $VotesMonth)  //If user voted in the same month in the same year (works)
								 	{
									//$printer2 = "X month on $x";
									if ($uid == $VotesEid) //If user voted in the same month in the same year on the same Entry (judged by the user number) (works)
										{  
										//$printer2 = "x uid match on $x";
										$x = "1";  //User has voted for this entry
										$printer = "It seems you have already voted for this entry.  You can not vote for an entry more than once..."; //do nothing, they have voted
										}	
								 	}
								}
							}

					$Xvotecontent = mysql_fetch_array($votecontent);	
				   	}//end of for loop
					//===========================
					//End check if user has voted
					//===========================


					
			
			

					//============================================================
					//Now we know what $x is we know if the user has voted or not
					//============================================================

					if ($x == "0")  //If user has not voted according to above loop
					{
			
					//==================================
					// Did User Choose a number or not?
					//==================================
					if ($choice != "Choose Rating")
					{
					//Do Database Entry stuff here
					$printer = "Your vote is about to be processed...<br />";
					
					//===========================================================================================
					//Let's check AGAIN if the user is all legit to stop BACK button and refresh button cheaters!
					//============================================================================================
					$votecontent = mysql_db_query($dbname, "SELECT * FROM votes ORDER BY id ASC");
					$Xvotecontent = mysql_fetch_array($votecontent);
					$Max = mysql_num_rows($votecontent);
					for ($loop=1; $loop<=$Max; $loop++)
					{ 
						$VotesEid = $Xvotecontent["eid"];
						$VotesUid = $Xvotecontent["uid"];
						$Votesrating = $Xvotecontent["rating"];
						$VotesMonth = $Xvotecontent["month"];
						$VotesYear = $Xvotecontent["year"];

						
						if ($VotesUid != $member_id) //If logged in user HAS voted
							$printer2 =  "BLIMEY!  x = $x";
							{
							if ($year != $VotesYear) //If user voted in the same year
								$printer2 =  "BLOWMEY!  x = $x";
								{
								if ($month != $VotesMonth)  //If user voted in the same month in the same year
									$printer2 =  "BLIBLEY!  x = $x";
								 	{
									if ($uid != VotesEid)  //If the user shows up in both tables
										$printer2 =  "BLOOKY!  x = $x";
										{
										if ($x != 1)  //If user has voted (this is handy if the loop gets triggered below then tries to get in again)
											{
											//If user voted in the same month in the same year on the same Entry
											$Add = mysql_db_query ($dbname, "INSERT INTO votes (id,uid,eid,rating,month,year)
					 						VALUES ('', $MemberId, $uid, $chosen, $month, '$year')") or die(Mysql_Error()); 
											$printer = "You chose to give entry number <b>$entryid</b> a score of <b>$chosen</b>... Data entered into database, your vote has been placed!"; //Tell em they have voted
											$x = "1";  //User has now voted... they cannot vote again.
											}
										}
								 	}
								}
							}
													
							
							
					$Xvotecontent = mysql_fetch_array($votecontent);	
				   	}//end of for loop
					//===========================================================================================
					//End of Let's check AGAIN if the user is all legit to stop BACK button and refresh button cheaters!
					//============================================================================================							

					}
					else
					{
					//They have not chosen
					$printer = "Sorry, you did not choose a number from 1 - 5...<br/>REMEMBER, you don't have to vote for EVERY entry, just the ones you want to.";
					}
					
					
					
					}
					//or if the user HAS already rated (ie: x == 1) then tell them they've rated and can't do it again
					else if ($x == "1")
					{
					$printer = "It seems you've already voted on this animation.  You can only vote once per animation"; //Tell em they have voted
					}


	//They mustn't be logged in so no, don't stress it... they can't do anything anyway 
	} 
	else 
	{
		$printer =  "You are not logged in!   If you wish to rate this animation please login or register.";
	}


?>






<table width="600" align="center" bordercolor="#333333">
<tr>
<td>
<?
//==============================
// Print the results HERE
//==============================
echo "$printer<br /><br />";
echo "Redirecting you to the voting page in a couple of seconds...<br />";
echo "If you don't get redirected, <a href = "../current_round.php">please click here</a>.<br/>";

//==========================================================================================================
//Note that $printer2 etc are just bug testing variables to print out where the code is at at various stages
//==========================================================================================================
//echo "$printer2<br /><br />";
//echo "X = $x<br>";
//echo "VotesUid = $VotesUid<br> member_id == $member_id<br>";


//=======================================================================================
// Redirect back to the voting page so cheaters can't refresh    Sloppy but effective
//=======================================================================================

$IE=eregi("MSIE",$HTTP_USER_AGENT); 
if ($IE==true) { 
header("Location: ../current_round.php"); 
exit; 
} 
$NN6=eregi("Gecko",$HTTP_USER_AGENT); 
if ($NN6==true) { 
header("Location: ../current_round.php"); 
exit; 
} 
$NN=eregi("mozilla",$HTTP_USER_AGENT); 
if ($NN==true) { 
header("Location: ../current_round.php"); 
exit; 
} 
else { 
header("Location: ../current_round.php"); 
exit; 
} 



?>
</td>
</tr>
</table>

</body>
</html>
Post Reply