Jump to content

Forgotten Password


Recommended Posts

The tokens are equivalent to passwords, because anybody who knows them can take over the account. That's why you need to protect them in the same way that you protect passwords.

 

An SQL injection attack that reveals all current tokens would be a disaster. Even worse: Since anybody can request a token, it's even possible to target specific accounts (e. g. admins).

Link to post
Share on other sites

Even worse: Since anybody can request a token, it's even possible to target specific accounts (e. g. admins).

Hmm, excellent point. That would be nasty.

 

EDIT: Although, that's kind of not solving anything. If you have an SQL injection vulnerability, couldn't you just change the column value for an admin's password or token? Or, promote yourself to admin level?

Edited by scootstah
Link to post
Share on other sites

If there's a vulnerability specifically within an “UPDATE users SET ...” query, then the entire authentication and authorization system is worthless.

 

But this is rare. Most attacks happen by finding any vulnerable query and using that to fetch secret data from arbitrary tables.

Link to post
Share on other sites

Did you read my explanation in #22?

 

I'd suggest that you forget about your current code for now and start with two fresh PHP scripts. The first script generates a token, sends it by e-mail and stores the hash in the database. Try it.

Link to post
Share on other sites

I dont understand how i can get rid of the vulnerability in the url you can change the username and token and take over accounts with my current code i don't understand how i can prevent this

You need to SELECT the user first, to make sure the information given is valid. Then you can perform the update.

Link to post
Share on other sites
  • 4 months later...

 

You're not supposed to store the plaintext token, but you do store its SHA-256 hash. To check if a token is valid, you hash it and search that hash in the database.

 

Generating a token:

<?php

// generate 16 random bytes
$rawToken = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);

// encode the random bytes and send the result to the user
$encodedToken = bin2hex($rawToken);

// hash the random bytes and store this hash in the database
$tokenHash = hash('sha256', $rawToken);

Looking up a token:

<?php

$encodedToken = $_GET['token'];

// decode the token and hash it
$rawToken = hex2bin($encodedToken);
$tokenHash = hash('sha256', $rawToken);

// now look up $tokenHash

 

 

Edit* Never mind. I see the mistake. It is in the comment what to send to user

 

I just got around to trying this and it seems to not make sense.

 

You generate (encode) the token hash and then store that in the DB. I assume that is also what is emailed to user.

Now it appears on lookup you decode the emailed token first, then compare to DB token, but this wont match since what was sent to user is exact match for what is stored in db.

 

Am I missing something?

Edited by benanamen
Link to post
Share on other sites

I send the original token (in some human-readable format), not the hash. The hash is used to protect the token from being stolen from the database, just like a password hash (after all, the token is equivalent to a password).

 

When the user submits the human-readable token, I transform it back into the original binary form, calculate the hash and check if that hash is stored in the database.

Link to post
Share on other sites

It is appearing that on the return trip to transforming the users token to match the binary version in the DB that an additional record identifier such as user_id is required to get the correct row to compare to. Since the users token is not the same as the DB token you cant do a SELECT dbtoken WHERE user token = DB token.

 

Am I correct in this? 

Link to post
Share on other sites

No. The (hexadecimal) hash of the submitted token is exactly the same as the stored hash. It's also effectively unique, so no further identifiers are required.

 

The workflow is like this:

 

generating:

raw_token := secure_rand(16)

mail(hex_encode(raw_token))

database_store(hash(raw_token))

 

validating:

raw_token := hex_decode(url_param("token"))

database_search(hash(raw_token))

Link to post
Share on other sites
This thread is more than a year old.

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.