tags:

views:

145

answers:

3

I need the following authentication script finished. I am weak at php/pdo so I do not know how to ask for the number of rows equalling one and then setting the session id's from the results of the query. I need to not only set the $_SESSION['userid'] but also the ['company'] and the ['security_id'] as well from the results.

here is what I have:

$userid   = $_POST['userid'];
$password = $_POST['pass'];
if ( $userid != "" || $password != "" )
{
  $sql = "SELECT * FROM contractors WHERE userid = '" . $userid . "' AND password = '" . $password . "'";
  $result = $dbh->query( $sql );
} else
{
  echo "login failed. Your fingers are too big";
}

Optional Information: Browser: Firefox

A: 
$userid   = $_POST['userid'];  
$password = $_POST['pass'];
if ((isset($userid) && $userid != "") || (isset($password) && $password != "")
{
  $sql = "SELECT * FROM contractors WHERE userid = '" . $userid . "' AND password = '" . $password . "'";
  $result = $dbh->query( $sql );
  $num_rows = mysql_num_rows($result);
  if($num_rows > 0)
  {
    echo "Login Success";
  }
  else
  {
    echo "Login Failed";
  }

} else
{
  echo "login failed. Your fingers are too big";
}

It is good to use COOKIE instead of SESSION Variable.

You have to replace the following code
echo "Login Success";

to the following code
$myrow = mysql_fetch_row($result); setcookies('USER_ID', $myrow[0]);

Tareq
cookies are as insecure as sessions, if not worse
knittl
The author stated he was using PDO, which will not work with mysql_num_rows.
notJim
+1  A: 

The php manual is an excellent resource for learning PHP. It looks like you know a little SQL, and you have heard of PDO, which is a good start. If you search google for "PDO", or look in the PHP manual for the term, you'll find the PDO section of the manual. It looks like you've found the ->query function, so now you need to see what that returns. Going to the that function's manual page, we see that it returns a PDOStatement object. The word PDOStatement is helpfully linked to the relevant page in the manual, which lists the methods available on that object. There is a rowCount() method that will likely do what you want.

notJim
NOTE: `rowCount()` will **not** work. Quoting from the documentation: *"For most databases, PDOStatement::rowCount() does not return the number of rows affected by a SELECT statement."*
Ilari Kajaste
Thank you notJim for your help. I really can't wait for the php manual to not read like greek to me.
Tom
+2  A: 

DO NOT EVER USE THAT CODE!

You have a very serious SQL injection open there. Every user input that you take, whether from cookies or CGI, or wherever, must be sanitized before it's used in an SQL statement. I could easily break into that system by attempting a login with an username like:

user'; UPDATE contractors SET password = '1337'

... after which I could then login as anyone. Sorry if I sound aggressive, but what that code does is like forgetting to lock the front door into your company which probably doesn't even contain an alarm system.

Note that it doesn't matter whether the input is actually coming from the user or not (perhaps it's in a pre-filled, hidden from). From the security point of view, anything that comes from anywhere outside has to be considered to contain malicious input by the user.

As far as I know, you need to use the quote function of PDO to properly sanitize the string. (In mysql, this would be done with mysql_real_escape_string().) I'm not an expert on PDO, mind you, somebody please correct if I'm wrong here.

Also you probably shouldn't store any passwords directly in the database, but rather use a hash function to create a masked password, then also create a hash from the user provided password, and match the hashes. You can use the PHP hash function to do this.

As for other issues, I don't know if the approach you have on SQL SELECT is the best approach. I would just select the corresponding user's password and try matching that in the program. I don't think there's any fault in the method you're using either, but it just doesn't seem as logical, and thus there's a greater chance of me missing some bug - which in case of passwords and logins would create a window for exploits.

To do it your way, you need to notice that the result you are getting from the PDO query is a PDOStatement, that doesn't seem to have a reliable function to diretly count the amount of result rows. What you need to use is fetchAll which returns an array of the rows, and count that. However, as I said this all feels to me like it's open for failures, so I'd feel safer checking the password in the code. There's just too much distance from the actual password matching compasion for my taste, in such a security-critical place.

So, to the get the resulting password for the userid, you can use PDOStatement's fetch() which returns the contents of the column from the result. Use for example PDO::FETCH_ASSOC to get them in an associative array based on the column names.

Here's how to fix it:

$userid_dirty   = $_POST['userid'];
$password_dirty = $_POST['pass'];
$success = false; // This is to make it more clear what the result is at the end
if ($userid != "" || $password != "") {
  $userid = $dbh->quote($userid_dirty);
  $passwordhash = hash('sha256',$password_dirty);
  $sql = "SELECT userid, passwordhash, company, security_id FROM contractors WHERE userid = ".$userid;
  $result = $dbh->query( $sql );
  if ($result) { // Check if result not empty, that userid exists
    $result_array = $result->fetch(PDO::FETCH_ASSOC);
    if ($result_array['PASSWORDHASH'] == $passwordhash) {
       // login success
       $success = true;

       // do all the login stuff here...
       // such as saving $result_array['USERID'], $result_array['COMPANY'], $result_array['SECURITY_ID'] etc. 

    } // else fail, wrong password
  } // else fail, no such user
} else {
  // fail, userid or password missing
  echo ' please enter user id and password.';
}
if (!$success) {
  echo ' login failed.';
}

Of course, the code can be cleaned up a bit, but that should explain what needs to be done. Note that since the password is both hashed, and never used in the SQL, it doesn't actually need cleaning. But I left it there just in case, since in the original code it was used in the query.

Note that all the code concerning storing passwords need to be changed to store the hash instead of the password. Also, it would be a very good idea to use a salt added to the password before hashing.

Also, I provided the code simply for educational purposes - I just thought that code was the clearest way to explain how to do this. So do not mistake this site as a service to request code. :)

Ilari Kajaste
Thank you very much LLari. I really appreciate the help. I know that the site is not a code service. I even posted a code service request on another site first and still got nothing. You should go on justanswer dot com. You can probably make some good money. Again a sincere thanks. $grateful_person = "tom";
Tom
No problem! I kinda figured it wasn't a code request, but thought it worth to mention to avoid misconceptions if some other reader comes to read this. And I definatelly suggest also salting those passwords (`password = hash(plain_password + salt)`), since hashes of most passwords can be pretty easily reversed with something called Rainbow Tables. Anyway, glad the answer helps, and happy coding Tom!
Ilari Kajaste