How to Prevent Two Users From Getting the Same Email Verification Code - php

Ok, now while I understand the chances of reproducing a verification code made up of some 50-100 random character is slim to none, do any of you guys do anything to hedge against the off chance that two users are provided with the same random verification code? I.e. Would you store these codes (tokens, whatever you want to call them) in a DB? Just wondering, logically, not even necessarily programmatically how you guys go about this or, even in the most secure systems, if it is even necessary. Thanks.

You have several options, depending on what php version you're using.
For PHP >= 7.1(I believe) you have random_bytes which returns a random series of bytes, you need to use bin2hex to get a readable series of characters.
For versions less that 7.x you can use openssl_random_pseudo_bytes. Notice the "pseudo" part. It's not truly random, but for your purposes it should be considered "random enough".
You can directly read from random or urandom if using a linux distro.
Read here about the differences between the two.
Storing them in the database is perfectly fine.
Do note that functions like rand aren't truly random. See here.
As for the question itself:
You don't really need truly random tokens for email verification. Normally email verifications are associated with, well, an email and usually have an expiration period (1, 2, 3 hours, whatever you want it to be), you you don't need them to be perfectly random just random enough.
For your purposes even str_shuffle would be good enough.
Don't over complicate things whenever possible.

Related

Can I provide an encrypted string to users and be sure it is safe for 1-2 hours

We were making kind of a simple game,
in which:
Users receive the next number of play as an encrypted string Before they play
After they play, the encryption password is provided to them to check the play number was correct.
Each encrypted string is only valid for 1-2 hours and number of play , verificating string and encrypted string is regenerated again after that time
The encrypted string includes a verification (5 char) code so both users and we can make sure Decryption process was successful
Sample Character to get Encrypted (QQ9LU is random verification code provided to user before the play):
Next Play Number: 8 - Verify String: QQ9LU
Sample Encrypted String (provided to user before play):
NXRykKOv3B6kuu4Ke3svp7HH3enNiqIZrJSXJiF54QkHHjtXgqpUXxyuP7YUNICeFLg==
Sample Password (provided after play):
Please note this is generated randomly for each encryption
FA00RDjA77hlOzcOzH6kuGcc29CyM7Hw
We use CodeIgniter 2.2.2 Encryption Class to encrypt/decrypt strings
Encryption Method Info:
Function Used: $this->encrypt->encode($msg, $pass); with random pass each time
Cipher is CodeIgniter 2 default MCRYPT_RIJNDAEL_256
Mcrypt mode is MCRYPT_MODE_CBC
My Questions are:
Can i trust that users cannot break the encrypted string (and know the number of play before they get the password) in 1-2 hours (aside from getting lucky)
Is placing random verification code Verify String: T3YH4 in there good or bad? does is affect security? (this is to verify decryption result was successful, also we added it because the only variable in each string was a single digit, for example only number 8 changes to 7, so we wanted to add more variable characters to the string to possibly have a better security)
Any other suggestion is appreciated
Short answers:
From a technical POV, what you're doing is unsafe, although it might be enough for just a 2-hour timeframe.
What you're trying to do here is called "message authentication", but that's not how it should be done, which in turn does impact security. You should use a HMAC instead.
My advice would be to upgrade to CodeIgniter 3 (CI2 will stop receiving even security updates in a few months) as soon as possible, and use its new Encryption library instead. That will make it safe for years, not hours.
Long answer:
The encryption library should do both encryption and authentication for you, but unfortunately the CI_Encrypt class itself is badly written and lacking a lot of functionality (such as authentication), which is why it was DEPRECATED and is being replaced by a new (CI_Encryption) library in CodeIgniter 3.
Explaining all the flaws in here would be quite the task, so I'd rather link you to an external article (not self-promoting, don't worry), which does that quite nicely if you're interested in the low-level details.
No matter which library you use however, one thing must be noted - a password is not the same thing as an encryption key.
Passwords have a varying length and are used by humans, which means that they must be readable by humans, and that in turn limits them to a certain set of characters.
Encryption keys on the other hand have a fixed length (each encryption algorithm is designed to work with a specific key length; for Rijndael-256 that's 32 bytes, which you seem to match) and are not limited to human-readable characters (which means more entropy and therefore more security) - they represent raw binary data.
Anything else can be controlled (and therefore automatically done) by a library, but if you pass a password instead of a key - that's what the library will use, so you should take care of that.
The best and simple way to do that is to use the filesystem functions to create a simple text file for each user in non public path with two lines, the first of them is a unique random string (long string varied in length) and the second is the number.
Then using sha1_file get the hash value of the file then store it in the database related to its path and creating time, then send this hash to the user.
After the user has played, check the value by another script that get the value of the hash from the database, then read the file and parse its second line to display the number.
By this way, you have gave the user a hash not for a string, but it for a file and cracking it to get the file back is not simple as to be done in two hours.
You are giving your Encryption/Decryption logic to client side. Hacker will easily identify how your password and encryption strings are being match.
Many framework have their own password creationg and compare logics. Yii using SALT and other features like SHA1 etc...
Keep it simple and keep all things at your end. Generate your encryption things and store at your end. Follow simple steps,
Generate encryption password (using SALT and/or other encryption tools) and store at your end
Ask client (user) to enter their password (key) and get at server side
Convert your password (key) to encryption password and compare
CPasswordHelper will be helpful for you. Try to download Yii source code and put out their logic for you.
Hope that helps !!
Sounds like a fun game!
I am assuming you are creating these strings in files on a filesystem. If you were hosting them on some web application that would assume different techniques to break the string.
Adding a code to the end of the string is called salting the string. While this makes the string harder to guess, if you are adding a hardcoded salt instead of a randomly generated salt it can still be easily broken by brute force methods.
I would try using a one-way hashed string for the password and storing that in a database. The user is unable to decrypt the string and has to just provide a matching password to gain access to your string. It is possible for programs to break one-way hashed strings but I find it unlikely someone will be smart enough to do that if they are in college and only have two hours. It takes alot of domain knowledge and experience to start generating one-way hashed strings to brute force it.
In addition you are probably safe with the method you are doing currently, students will not likely be able to break a string in 2 hours unless they are familiar with advanced encryption hacking scripts that take some work to find. I am guessing they will do trial and error, using different decryption libraries similar to the example you provide and hoping they get lucky with the library of strings they are trying to match against yours.
Also information is important with any type of encryption. Telling someone you are adding a 5 code salt to your string, will give them some insight into how your encryption algorithm works. They can then try methods of breaking it based on the information you give them. Try the same thing with your own algorithm and leave the students in the dark, I doubt anyone will break anything in the time alotted. Alot of hacking techniques involve going through an information gathering process where the hacker scopes out or maps a system before trying to attack it.

HASH for GIF IMAGES

I need to know if exists any form to get a unique hash from gif images, i did tried with SHA1 file function
sha1_file
but i don't know if exist the case where two hash of different gif images, result in same hash.
Its can happen with SHA1? In this case is better SHA2, or MD5? Or any other previously implemented in PHP language.
I know its also depends of file size, but gifs image don't exceed 10mb in any case.
I need recommendations for this problem. best regards.
There is no hash function that creates different values for each and every set of images you provide. This should be obvious as your hash values are much shorter than the files themselves and therefore they are bound to drop some information on the way. Given a fixed set of images it is rather simple to produce a perfect hash function (e.g. by numbering them), but this is probably not the answer you are looking for.
On the other hand you can use "perfect hashing", a two step hashing algorithm that guarantees amortized O(1) access using a two step hashing algorithm, but as you are asking for a unique 'hash' that may also not be what you are looking for. Could you be a bit more specific about why you insist on the hash-value being unique and under what circumstances?
sha1_file is fine.
In theory you can run into two files that hash to the same value, but in practice it is so stupendously unlikely that you should not worry about it.
Hash functions don't provide any guarantees about uniqueness. Patru explains why, very well - this is the pigeonhole principle, if you'd like to read up.
I'd like to talk about another aspect, though. While you won't get any theoretical guarantees, you get a practical guarantee. Consider this: SHA-256 generates hashes that are 256 bits long. That means there are 2256 possible hashes it can generate. Assume further that the hashes it generates are distributed almost purely randomly (true for SHA-256). That means that if you generate a billion hashes a second, 24 hours a day, you'll have generated 31,536,000,000,000,000 hashes a year. A lot, right?
Divide that by 2256. That's ~1060. If you walked linearly through all possible hashes, that's how many years it would take you to generate all possible hashes (pack a lunch). Divide that by two, that's... still ~1060. That's how many years you'd have to work to have a greater than 50% chance of generating the same hash twice.
To put it another way, if you generate a billion hashes a second for a century, you'd have a 1/1058 chance of generating the same hash twice. Until the sun burns out, 1/1050.
Those are damn fine chances.

Methods for generating 'random' codes for use with physical/offline verification? PHP/WEB

Long story short, I want to create an automated gift certificate system. I have decided that since the authentication system is largely manual (scan qrcode/input qc code), there is little chance for bruteforce. (I am sure after the hundredth try, we'd just kick the dude out.)
As such, the gift code will be a mix of a sequential GC(Gift Code) ID. And some sort of hash/code unique to that sequential ID. IE. CODE_1001 // SHA1HASHBLAHBLAH.
This allows for a human (ie. server) readable code to match with a unique tag for verification.
Specifically, I am wondering what the best practice might be in this case.
Do I generate a totally random code in a large space and assume there will be no collision between the pair of GCID and UniID? Or somehow salt the generated code with the sequential key?
http://php.net/manual/en/function.uniqid.php would be my try, I've used this function a lot to generate unique values without collision.
or use: http://www.php.net/manual/en/function.openssl-random-pseudo-bytes.php
This may help.
$var = mysql_real_escape_string(md5($var['value']));
or
$var = mysql_real_escape_string(md5($var));
or
$var = mysql_real_escape_string(sha512($var['value']));
or
$var = mysql_real_escape_string(sha512($var));

PHP - Looking for a two way obfuscation method for storing phone numbers

I'm looking to store (in mySQL) an obfuscated version of a phone number, where the number is used for authentication (I need to be able to get back the original number).
I've thought about an arbitrary scheme like storing the number * 15 or some constant only my app knows.
What are some better ways of doing this?
EDIT: Some things I'd like to clarify:
The phone numbers that are saved can be used to log into an iPhone app - so I want users to be able to see which number they have connected to the service incase they want to log into the app with a different number later. This means I cannot hash the value.
Essentially I am looking for a way to protect the data if someone lifts my database that they don't have a bunch of phone numbers in raw form. So I'd like to obfuscate them so I can use them for authentication, but be able to get one back in its original form without storing it raw.
EDIT: To clarify, I am not authenticating on JUST the phone number. If implemented, it would be phone number + a password! Enter a single string of digits that may exist and you're in? lol - my apologies if I have misled some folks.
Store where? In a database? Use an encryption function rather than rolling your own system.
In MySQL it'd be as simple as:
INSERT INTO users (phone) VALUES (AES_ENCRYPT('yourkey', '867-5309'));
of course, now you're changed the problem from hiding the phone numbers to "where the #$##$## can I hide this key?". Obvious solution: hide the key under a rock outside your server's front-door. Which changes the problem into "where the ####$###% can I hide this rock?". Obvious solution: cover your front yard with a steel cage with a padlock on the door. New problem: how to hide the padlock key... and so on.
How about actual encryption? In this scenario, a good symmetric encryption algorithm is trivial, since the length of the payload is limited to, what, 10 digits, so you can get by with a key that's also 10 decimal digits long; using such a key, all you need to do is something like XOR or increment / mod 10 on each digit. Of course, the weak link in this scheme then is the way you store the key.
I am curious, however, why you need to get them back out - if it's for authentication:
you shouldn't be using phone numbers, as these are easy to look up, even automatically
you should be storing secure one-way hashes with individual salts, so you couldn't even get them back out youself if you wanted to (except by brute-forcing)
Using the Cipher Class you can do this:
$phone = '...';
$key = 'secret.for.each.number';
$phone = Cipher::encrypt($phone, $key);
Before you store it in the database. Then later you can pull it out and do this:
$phone = Cipher::decrypt($phone, $key);
A better way would be not doing that. There is a reason one-way encryption is used to store passwords.
If you need to get back the original value, you should not be using it for authentication, since it will invariably be easy for an attacker to find it.
If you feel you need to hide the value by obfuscating it, you probably need to change something fundamental about how you're storing the data.
This isn't a very good approach to security. Several things jump out at me:
Phone numbers are very easy to guess: just program something to start guessing random combinations. Encrypted or not, your program is validating using these numbers, so it will eventually work on some. You need an extra layer of security like a password known only to the user in question. I would recommend anti-brute-force attack measures as well.
Any two-way encryption can be cracked, it is as simple as that. If you need to be able to decrypt data in the database easily, the only benefit from encrypting it is if someone hacks into your database and grabs the information. As others have pointed out, if that happens, you have bigger issues. The other scenario is for staffers who could have valid access to the DB. If you are hiding the data from them, it is important to encode the information in some way. But multiplying the phone number by a "unknown" constant is not ideal. Use a better method.
Surely I know my friend's numbers, so I could hack into anyone's account, correct? You need to add a password component if you haven't already. The password should be 1-way encryption using a strong and unique SALT. Once added, you only need to encrypt phone numbers in the DB if you don't want your staffers to see them. Otherwise you are wasting time encrypting them.
There is no point in this question.
Just leave these phone numbers as is. You will gain no security improvement from such obfuscation

Unique key generation

I looking for a way, specifically in PHP that I will be guaranteed to always get a unique key.
I have done the following:
strtolower(substr(crypt(time()), 0, 7));
But I have found that once in a while I end up with a duplicate key (rarely, but often enough).
I have also thought of doing:
strtolower(substr(crypt(uniqid(rand(), true)), 0, 7));
But according to the PHP website, uniqid() could, if uniqid() is called twice in the same microsecond, it could generate the same key. I'm thinking that the addition of rand() that it rarely would, but still possible.
After the lines mentioned above I am also remove characters such as L and O so it's less confusing for the user. This maybe part of the cause for the duplicates, but still necessary.
One option I have a thought of is creating a website that will generate the key, storing it in a database, ensuring it's completely unique.
Any other thoughts? Are there any websites out there that already do this that have some kind of API or just return the key. I found http://userident.com but I'm not sure if the keys will be completely unique.
This needs to run in the background without any user input.
There are only 3 ways to generate unique values, rather they be passwords, user IDs, etc.:
Use an effective GUID generator - these are long and cannot be shrunk. If you only use part you FAIL.
At least part of the number is sequentially generated off of a single sequence. You can add fluff or encoding to make it look less sequential. Advantage is they start short - disadvantage is they require a single source. The work around for the single source limitation is to have numbered sources, so you include the [source #] + [seq #] and then each source can generate its own sequence.
Generate them via some other means and then check them against the single history of previously generated values.
Any other method is not guaranteed. Keep in mind, fundamentally you are generating a binary number (it is a computer), but then you can encode it in Hexadecimal, Decimal, Base64, or a word list. Pick an encoding that fits your usage. Usually for user entered data you want some variation of Base32 (which you hinted at).
Note about GUIDS: They gain their strength of uniqueness from their length and the method used to generate them. Anything less than 128-bits is not secure. Beyond random number generation there are characteristics that go into a GUID to make it more unique. Keep in mind they are only practically unique, not completely unique. It is possible, although practically impossible to have a duplicate.
Updated Note about GUIDS: Since writing this I learned that many GUID generators use a cryptographically secure random number generator (difficult or impossible to predict the next number generated, and a not likely to repeat). There are actually 5 different UUID algorithms. Algorithm 4 is what Microsoft currently uses for the Windows GUID generation API. A GUID is Microsoft's implementation of the UUID standard.
Update: If you want 7 to 16 characters then you need to use either method 2 or 3.
Bottom line: Frankly there is no such thing as completely unique. Even if you went with a sequential generator you would eventually run out of storage using all the atoms in the universe, thus looping back on yourself and repeating. Your only hope would be the heat death of the universe before reaching that point.
Even the best random number generator has a possibility of repeating equal to the total size of the random number you are generating. Take a quarter for example. It is a completely random bit generator, and its odds of repeating are 1 in 2.
So it all comes down to your threshold of uniqueness. You can have 100% uniqueness in 8 digits for 1,099,511,627,776 numbers by using a sequence and then base32 encoding it. Any other method that does not involve checking against a list of past numbers only has odds equal to n/1,099,511,627,776 (where n=number of previous numbers generated) of not being unique.
Any algorithm will result in duplicates.
Therefore, might I suggest that you use your existing algorithm* and simply check for duplicates?
*Slight addition: If uniqid() can be non-unique based on time, also include a global counter that you increment after every invocation. That way something is different even in the same microsecond.
Without writing the code, my logic would be:
Generate a random string from whatever acceptable characters you like.
Then add half the date stamp (partial seconds and all) to the front and the other half to the end (or somewhere in the middle if you prefer).
Stay JOLLY!
H
If you use your original method, but add the username or emailaddress in front of the password, it will always be unique if each user only can have 1 password.
You may be interested in this article which deals with the same issue: GUIDs are globally unique, but substrings of GUIDs aren't.
The goal of this algorithm is to use the combination of time and location ("space-time coordinates" for the relativity geeks out there) as the uniqueness key. However, timekeeping is not perfect, so there's a possibility that, for example, two GUIDs are generated in rapid succession from the same machine, so close to each other in time that the timestamp would be the same. That's where the uniquifier comes in.
I usually do it like this:
$this->password = '';
for($i=0; $i<10; $i++)
{
if($i%2 == 0)
$this->password .= chr(rand(65,90));
if($i%3 == 0)
$this->password .= chr(rand(97,122));
if($i%4 == 0)
$this->password .= chr(rand(48,57));
}
I suppose there are some theoretical holes but I've never had an issue with duplication. I usually use it for temporary passwords (like after a password reset) and it works well enough for that.
As Frank Kreuger commented, go with a GUID generator.
Like this one
I'm still not seeing why the passwords have to be unique? What's the downside if 2 of your users have the same password?
This is assuming we're talking about passwords that are tied to userids, and not just unique identifiers. If that's what you're looking for, why not use GUIDs?
You might be interested in Steve Gibson's over-the-top-secure implementation of a password generator (no source, but he has a detailed description of how it works) at https://www.grc.com/passwords.htm.
The site creates huge 64-character passwords but, since they're completely random, you could easily take the first 8 (or however many) characters for a less secure but "as random as possible" password.
EDIT: from your later answers I see you need something more like a GUID than a password, so this probably isn't what you want...
I do believe that part of your issue is that you are trying to us a singular function for two separate uses... passwords and transaction_id
these really are two different problem areas and it really is not best to try to address them together.
I recently wanted a quick and simple random unique key so I did the following:
$ukey = dechex(time()) . crypt( time() . md5(microtime() + mt_rand(0, 100000)) );
So, basically, I get the unix time in seconds and add a random md5 string generated from time + random number. It's not the best, but for low frequency requests it is pretty good. It's fast and works.
I did a test where I'd generate thousands of keys and then look for repeats, and having about 800 keys per second there were no repetitions, so not bad. I guess it totally depends on mt_rand()
I use it for a survey tracker where we get a submission rate of about 1000 surveys per minute... so for now (crosses fingers) there are no duplicates. Of course, the rate is not constant (we get the submissions at certain times of the day) so this is not fail proof nor the best solution... the tip is using an incremental value as part of the key (in my case, I used time(), but could be better).
Ingoring the crypting part that does not have much to do with creating a unique value I usually use this one:
function GetUniqueValue()
{
static $counter = 0; //initalized only 1st time function is called
return strtr(microtime(), array('.' => '', ' ' => '')) . $counter++;
}
When called in same process $counter is increased so value is always unique in same process.
When called in different processes you must be really unlucky to get 2 microtime() call with the same values, think that microtime() calls usually have different values also when called in same script.
I usually do a random substring (randomize how many chars between 8 an 32, or less for user convenience) or the MD5 of some value I have gotten in, or the time, or some combination. For more randomness I do MD5 of come value (say last name) concatenate that with the time, MD5 it again, then take the random substring. Yes, you could get equal passwords, but its not very likely at all.

Categories