I have writen the following script. Everything works in my application, except the validation keeps returning to login. But I have read a lot about my issue, and everything seems right, but of course there should be something wrong otherwise it would work properly.
In my case a user logs in, a token is stored in the database and in a cookie.
For the creation of the token I use:
bin2hex(openssl_random_pseudo_bytes(16));
What I did next is setup a page that first checks if the cookie token and token in the database match. To be sure I first echo them both and both give the same token. I did it like this:
include 'mydatabase.php';
$cookie_name = "My_cookiename";
$result = mysql_query("SELECT * FROM users WHERE token='{$_COOKIE[$cookie_name]}'");
while($row = mysql_fetch_array($result)) {
echo $row['token'];
echo $_COOKIE[$cookie_name];
}
Ok so I am sure at this point the cookie token and database token match.
Now I want to compare them with an if/else. And here I am going wrong, because I can't get it to work. What I have now is this:
$result = mysql_query("SELECT * FROM users WHERE token='{$_COOKIE[$cookie_name]}'");
while($row = mysql_fetch_array($result)) {
if ($row['token'] != $_COOKIE[$cookie_name]) {
header('Location:myloginpage.php'); exit(); } else { // MY PAGE CONTENT IF MATCH }
I think there is something wrong with the line:
if ($row['token'] != $_COOKIE[$cookie_name])
Any help would be great, because I am really stuck at this point.
As the comments on your question have said you are checking things needlessly. The mysql query itself does the token checking for you
include 'mydatabase.php';
$cookie_name = "My_cookiename";
$result = mysql_query("SELECT * FROM users WHERE token='{$_COOKIE[$cookie_name]}'");
if (mysql_num_rows($results) != 1) {
header('Location:myloginpage.php');
exit();
}
// Content for your page goes here, no need for an else because of exit
I think I just solved it :D
I was having the same issue, I took the & sign out of my random token generator. when I surrounded the cookie string with htmlentities() I noticed the & signs were replaced with &, because strings usually read & as code. once I removed & from the tokens, it worked. Hope this helps.
Related
Something weird is happening with the following code. Instead of completely redirecting. It loads the page of the redirect into the login page and mixes things up.
Q1: How do i make a complete redirect.
- session start is the first line
- There's nothing being output before header.
- As for spaces, I'm not sure what will count as a space in the below script.
Q2: How do i preg_replace a string to only allow both lower cases and uppercases and 0 - 9 numbers and again how do i preg replace emaail to allow the '#' charecter and alphanumerics.
Q3: What's the best way to check if the user trying to login matches exactly the registered user?
Q4: What danger can a hacker do with my session variables?
PHP CODE
<?php
session_start();
require_once 'db_conx.php';
$email = preg_replace ('#[^A-Z, 0-9 ]#i', '', $_POST['email']);
$pwd = preg_replace ('#[^A-Z, 0-9 ]#i', '', $_POST['pwd']);
if ($uname == '' || $pwd == ''){
echo '<span style="color:#F00">Please fill in all login details.</span>';
} else {
$Result = mysql_query("SELECT * FROM users WHERE uemail = '$uname' && pwd = '$pwd'")
or die (mysql_error());
while($row = mysql_fetch_array($Result)){
$_SESSION['Sname'] = $row['firstname'];
$_SESSION['Slname'] = $row['lastname'];
$_SESSION['SUid'] = $row['uid'];
$_SESSION['Semail'] = $row['uemail'];
$_SESSION['Suid'] = $row['uid'];
$_SESSION['Szip'] = $row['zip'];
}
if (mysql_num_rows($Result) > 0){
header ('Location: ../user.php');
} else {
echo '<span style="color:#F00">Your account details do not match, please check your details and try again or try to recover your account if you forgot your password</span>';
}
}
?>
Thanks.
Q1
instead of using header( 'Location...)
you can use
echo '<meta http-equiv="refresh" content="0; URL= http://something.com">';
EDIT
i believe you can also use the following. the die should allow for the redirect, but in my experience it doesn't always get along with jquery.
header('Location: http://something.com');
die();
This is especially useful if you are using event.preventDefault(); in jquery on the same page, which will almost always cause header location redirects to be ignored. this method is also appropriate when you are using get requests to include a php page in your index file, causing a url like http://somesite.com/index.php?page=home
EDIT the above information was wrong it wasn't working for me because php had already sent the headers. i'm an idiot.
instead of this meta refresh, you could do this which should produce the desired result.
echo '<script type="text/javascript">window.location = "yoururlhere"</script>';die;
Q2
$step1 = preg_replace('#[^A-Z, 0-9 ]#i', $_POST["variable"]);
$step2 = strtolower($step1);
echo $step2;
Q3
This is a tough question to answer, but basically you want to hash there password, then check if it matches the password in the db. heres a brief pseudocode.
$username = $db->real_escape_string(strip_tags($_POST["username"]));
$password = hash('sha512', $salt.$_POST["Password"});
$db->query("SELECT * FROM `usertable` WHERE `Username`='$username' AND `Password`='$password' AND Username IS NOT NULL AND Username != '' LIMIT 1");
$result = $db->get();
if(!$result){
//the query returned a null result, so the username or password was incorrect.
}else{
//set user session and log them in.
}
Q4
I'm no expert, but it all depends on the architecture of your application and how you are setting sessions and cookies.in my opinion look into using formkeys and preventing xss, rfi, sql injection and lfi, then worry about session variables. the experience gained tackling the aforementioned problems will give you confidence and a broader understanding when attempting to secure your user sessions.
further information can be obtained from php.net/manual/en/session.security.php and stackoverflow.com/questions/328/php-session-security
thanks to the suggestions of DanFromGermany who improved on this answer.
Here is the first question and I need your help.
I transfer form data from first page using header location method in php to second page.
On the second page I accept the data using get.
Now here the url of 2nd page, after the data is sent (i.e. form is submitted)
http://mydomain.com/site1/form1_conf.php?id=123
When user is on second page, the data on second page is being displayed according the id number from the mysql database.
Now the problem is that when the user is on second page and he changes the number (for ex. 123 to say 78) the data of id=78, from the database is displayed, which is no good.
How can I stop that?
Please Note: I can't use post, nor can I use sessions.
EDITE:
php code on first page, to transfer to second page:
// after all validations are okay
$insert = //insert into database
$result = mysql_query($insert);
if($result)
{
echo("<br>Input data is succeed");
$lastInsertedId = mysql_insert_id();
header('Location:form1_conf.php?id='.$lastInsertedId); //THIS IS THE IMPORTANT LINE
}
else
{
$message = "The data cannot be inserted.";
$message .= "<br />" . mysql_error();
}
Your problem is not with the URLs: to a power user changing cookies or POST-variables is as trivial as editing GET-variables for a regular user. You'll need some way to 'sign' the requests as being valid.
Easiest to do this is with a "pre-shared key", which you use with one-way hashes to validate requests.
Redirector:
$newURL = '/newpage?id='.$id.'&hash='.sha1('mypresharedkey'.$id);
header('HTTP/1.1 303 See other');
header('Location: '.$newURL);
die;
The other page:
$idToShow = $_GET['id'];
$hash = sha1('mypresharedkey'.$id);
if($hash != $_GET['hash'])
die("Tssss, don't play with the address bar!");
else
RenderThePage();
This ensures end users can only access pages they've been allowed to by the submit.
For your specific code:
...all prior code
$lastInsertedId = mysql_insert_id();
$timestamp = time();
header('Location:form1_conf.php?'.http_build_query([
'id' => $lastInsertedId,
'time' => $timestamp,
'hash' => sha1('some-generated-key'.$timestamp.$lastInsertedId)
]);
In the other page, including a timebomb if you want (otherwise just comment it out):
$id = $_GET['id'];
$time = $_GET['time'];
if($_GET['hash'] != sha1('some-generated-key'.$time.$id))
die('URL was tampered with');
if(time() - $time > 300)
die('URL was only valid for 5 minutes');
You need to track the user and the id that they have in your database to make sure that they haven't changed the number. So when you get the information via the GET you make sure that it is legit.
Users can change the id or even attempt to go directly to that page via the url. So you need some sort of server-side check to verify that it is ok.
You could complicate this "cheating" a bit, if you didn't pass the ID number directly, but somehow encrypted it.
Let's say, you define a salt:
define(SALT, 'long weird salt with special characters etc.');
Here comes the first part you want:
$lastInsertedId = mysql_insert_id();
$querytag = base64_encode($lastInsertedId); // just to make it less readable
$checksum = md5($querytag . SALT); // and make a hash
header('Location:form1_conf.php?id=' . $querytag . '&checksum=' . $checksum);
At the beginning of form1_conf.php, you put this:
$encodedId = $_GET['id'];
$oldChecksum = $_GET['checksum'];
$newChecksum = md5($encodedId . SALT);
$id = base64_decode($encodedId);
if($newChecksum != $oldChecksum) {
die('You Are Cheating!');
}
... do something with the $id ...
The point is that since you add SALT to the hash, some user can't simply use md5 on a changed ID, because he's missing the SALT you used.
It'd be even better if the salt wasn't the same every time.
You should never trust the url because there is always a way to manipulate the data.
So you should do validation after retreiving the data. If the result does not fit you: for example the loggedin user with the ID = 1 requests the settings page from the userid = 3 you do not show the result.
<?php
$userID = $_GET['id'];
if($userID != $expectedResult)
{
//show errormessage, redirect or show the page with the users data
}
?>
Does someone know why this cookie doesn't wanna work, I been trying a lot of different things but it doesn't wanna make a cookie at all.
Script I'am using:
$sql = mysql_query("SELECT id FROM plattegrond_gebruikers WHERE email = '$username' AND password = '$password' LIMIT 1")or die(mysql_error());;
if(mysql_num_rows($sql) > 0){
$row = mysql_fetch_assoc($sql);
// User found, now let's create the cookies for the user!
if(!$_COOKIE["userid"]) {
setcookie("userid",$row["id"],time()+3600,'/','nieuws.holapress.com');
if(isset($_COOKIE['userid'])){
$cookieSet = 'The cookie is ' . $_COOKIE['userid'];
} else {
$cookieSet = 'No cookie has been set';
}
echo $cookieSet;
}else{
echo"cookie excists";
}
return true;
} else {
return false;
}
Everything works like it should, it makes the query, it gets the users information but it just doesn't set a cookie, and after login I get the "No cookie has been set". does anyone know what I'm doing wrong?
Probably you checking on local machine with parameter nieuws.holapress.com. Change it to your localhost.
The cookie can be read after reloading the page, because the first time you set the cookie, it will be send to browser, the browser will save it, then, for next requests, the browser include the cookie, and the server can read it.
You need to put in 1 line: session_start(); In all pages
So i'm basically messing around with my own cms type system at the moment and running into some problems with php sessions. Below is a rough explanation on what i have,
All the SQL is working fine as if i remove the sessions i get no login errors (unless i put in incorrect credentials),
$query = "SELECT * FROM `test` WHERE username='$user' AND password='$pass_md'";
$result = mysql_query($query) or die("Error: " . mysql_error());
$rows = mysql_num_rows($result);
$data = mysql_fetch_assoc($result);
if($rows == 1){
$_SESSION['expire'] = time() + (10 * 60);
$_SESSION['id'] = $data['id'];
header("Location: admin.php");
}
else {
header("Location: ulogin.php?login=failed");
}
So in admin.php i have this,
<?php
session_start();
if(!(isset($_SESSION['id']))){
header("Location: ulogin.php");
}
?>
My issue is it is logging me in and then passing me straight back to ulogin.php so i'm assuming i have an empty session however i am inserting the user id into the session.
Any help would be greatly appreciated, i'm probably missing something pretty obvious, i'm not the most advanced php developer so yeh, need some more eyes on it.
Thanks
Found the issue, because i was using 2 seperate login pages (One for the frontend and one for the backend) i was missing;
<?php
session_start();
?>
from one of my login pages, sorted now, thanks all for the comments that actually made me triple check that!
Can anyone tell me why this code is not working?? Any silly mistakes I made?
The Problem:
There is a login page. In the Login page i type in the ID and password and click enter. Once i click enter it will run the next file which is login_now.php. In my database, I have 2 entries. First entry the position is manager and 2nd entry position is staff. Logging in with manager is very successful while logging in with staff is a total failure...failure as in it never do what it should do it just return me back to log in page.
This is the code that is in login_now.php and this is what it suppose to do when enter button is clicked:
$query = "select * from emp where EID = '$myeid' and PASS = '$mypassword'";
//run the query
$result = mysql_query($query, $conn);
$row = mysql_fetch_assoc($result);
//found a record?
if (mysql_num_rows($result) > 0 and $row['POSITION']=="manager")
{
$_SESSION['eid'] = $myeid; //remember name as a session variable
$_SESSION['password'] = $mypassword; //remember password as a session variable
header('Location: welmanager.php'); //redirect user to index
}
elseif (mysql_num_rows($result) > 0 and $row['POSITION']=="staff")
{
$_SESSION['eid'] = $myeid; //remember name as a session variable
$_SESSION['password'] = $mypassword; //remember password as a session variable
header('Location: welstaff.php'); //redirect user to index
}
else
{
header('Location: login.php'); //kick back to login
}
Let me know if more codes in the login.php should be shown here. Thanks in advance.
A minor error may locate in if condition.
if (mysql_num_rows($result) > 0 and $row['POSITION']=="manager")
You have to use or condition rather than and,
if (mysql_num_rows($result) > 0 || $row['POSITION']=="manager")
Without wanting to jump on the bandwagon, the comments about session management being a solved problem are right - even if you chose not to use it, you can learn a lot from how they do it. Look at CakePHP, the Zend Framework, Symphony, even PEAR.
Secondly - SQL Injection! Even if this is not exposed to the wider internet, you can't necessarily guarantee that none of your staff are malicious.
Thirdly, it appears you store your passwords in plain text; this is a big nono. People often re-use their passports; someone who can steal your user records (using SQL Injection) can try those passwords on online banks etc. Read up on hashing passwords.
Fourthly, don't store the password in plaintext anywhere - but certainly not in the session object. You've already cover that...
The actual code looks syntactically okay, but there are some odd things.
if (mysql_num_rows($result) > 0 and $row['POSITION']=="manager")
Doesn't make sense! If there are no results, logically the $row array should be empty.
You're also not really distinguishing between legit "there's no match for username/pwd" situations and bugs such as having STAFF rather than staff in the type column.
I'd refactor it as:
$result = mysql_query($query, $conn);
$row = mysql_fetch_assoc($result);
if (mysql_num_rows($result) == 0)// no match!
{
header('Location: login.php'); //kick back to login
}
//Maybe put in a catch for more than 1 record too - that would be a data bug.
$_SESSION['eid'] = $myeid; //remember name as a session variable
switch($row['POSITION']){
case "manager":
header('Location: welmanager.php'); //redirect user to index
break;
case "staff":
header('Location: welstaff.php'); //redirect user to index
break;
default:
echo ("Found unknown staff type. Error.");
}
Now you can see whether your record really isn't found - i.e. the username/pwd combo didn't match - or whether the user profile isn't of type "staff".