2

in my system users register with their email address and receive a temporary link to log in.

hostname/login/OYkwIJt6be1V5kMg10G
  1. The token must be generated from the email adress of user and valid for 2 hours.
  2. I don't want to store a session or token in a given database

In my mind I imagine creating the link like this:

$token = md5(((email + time() + SALT))
$link = $host.$path.$token

Is this a good way to process? What would be the cleanest, simplest and easiest method to manage?

The USER table schematic looks like this:

CREATE TABLE IF NOT EXISTS `users` (
    `id` int(10) NOT NULL AUTO_INCREMENT,
    `email` varchar(100) NOT NULL,
    `first_name` varchar(100) NOT NULL,
    `last_name` varchar(100) NOT NULL,  
    `ip_adress` varchar(100) NOT NULL,
    `status` varchar(100) NOT NULL,
    `created` date NOT NULL,
    `last_login` varchar(100) NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1;

thank you for your recommendations

Edit

I opted for this solution according to your recommendations.

the best solution I found is using OpenSSL. It is built into PHP and you don't need any external library.

sample:

function encrypt($key, $payload) {
  $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
  $encrypted = openssl_encrypt($payload, 'aes-256-cbc', $key, 0, $iv);
  return base64_encode($encrypted . '::' . $iv);
}

function decrypt($key, $garble) {
    list($encrypted_data, $iv) = explode('::', base64_decode($garble), 2);
    return openssl_decrypt($encrypted_data, 'aes-256-cbc', $key, 0, $iv);
}

$email = "[email protected]";
$expire = time()+7200;
$data = $email.'-'.$expire;

$secret = 'h6k8TG2x03';

/* encrypt */
$token = encrypt($secret, $data);

/* user auth */
http://domain.com/?token=YSBzbGlnaHRseSBsb25nZXIgdGVzdCBmb3IgdGV2ZXIK==

/* decrypt */
$decrypted = decrypt($secret, $_GET['token']);
6
  • One issue I see here is that you appear to be using a hard-coded secret. This is not a good practice for security. Are you inserting a record in the users table at the time you create this link or at the time of confirmation?
    – JimmyJames
    Commented Nov 19, 2019 at 15:46
  • @JimmyJames no. But I think understand the idea behind your question.
    – Mary
    Commented Nov 19, 2019 at 15:50
  • I take no to mean after confirmation?
    – JimmyJames
    Commented Nov 19, 2019 at 15:52
  • @JimmyJames I have more confidence in concealing SALT hard in the code instead in the database. Maybe I'm wrong in my raisonnnement?
    – Mary
    Commented Nov 19, 2019 at 15:56
  • So a salt and a secret are two different things. Salts do not need to be secret but as Sean Burton notes, should not be shared between users. Your secret is the key to the encrypted data. The problem with hardcoding it is that it will tend to become not a secret. At the very least, I would recommend generating a new random secret (key) every hour and checking against the current and prior secrets. Do you have a place you can store and retrieve two secrets?
    – JimmyJames
    Commented Nov 19, 2019 at 16:57

3 Answers 3

3

If the token is not stored in the system then the system must be able to read the information (i.e. email, created time) from the token itself. That means you have to do encryption instead of one way hash.

How to do the encryption is already explained in here

2
  • The OP needs to authenticate the information, not encrypt it.
    – bdsl
    Commented Nov 19, 2019 at 10:59
  • Symmetric encryption is perfectly valid solution for generating temporary login link and validating it. Commented Nov 19, 2019 at 11:16
2

You want to generate a message on the server, send it by email, then have someone recieve the email and give the message back to you. You'll check that the message is authentic before letting them log in.

So you're looking for a Message Authentication Code (MAC). This requires you to have a secret you keep on the server and follow a MAC algorithm that has been described and found to be hard to break by multiple cryptography researchers to generate and check an authenticated message.

In general with anything cryptography related you should look for techniques that are well known in the literature and considered appropriate for your particular use case, rather than trying to invent anything of your own, unless you are in the business of cryptography research. (And even if you are in that business, probably don't use your own techniques until after publishing them as research and having other people study them for years and reccomend them)

One implementation of MAC you might want to consider is the PHP built in function hash_hmac.

0
1

The way you have capitalised the SALT and don't seem to be including it in the link seems to suggest that you would be using the same salt for every hash? If so, this defeats the purpose of using a salt.

If you're going to use a hash with a salt then you must generate a new salt for each hash, then include the salt in the token you return so it can be verified. Otherwise the token values will be predictable and could potentially be guessed by an attacker.

Of course, using encryption to encrypt the token as suggested in the other answers is another good way of making the tokens unpredictable.

2
  • What the OP is calling SALT is really functioning as a secret, not a salt, and it needs to stay secret. If it was included in plaintext with the token then an attacker could make up their own secret and make a forged token with it.
    – bdsl
    Commented Nov 19, 2019 at 19:24
  • That makes sense, in that case it's being used more like a pepper than a salt. Commented Nov 20, 2019 at 21:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.