Flaw in laravel hash - laravel

we are using Laravel Framework 5.7.15 with PHP version: 7.2.14-1
and we use below code to generate temporary password then hash it in the database.
In around 80 times all passwords hash matched the string however there were around 3 not matched strings , I searched for a cause and nothing appeared...
$input['tmp_password'] = substr(str_shuffle("0123456789"), 0, 4); // Random four digits
$input['password'] = Hash::make($input['tmp_password']);

As stated in the comments there are better ways to generate random passwords other than using str_shuffle. Using this method the passwords generated will always contain the same given chars just in a different order, making it easy to guess.
One example of a better way is using the helper method random from Str class
use Illuminate\Support\Str;
$password = Hash::make(Str::random(40)); // 40 being the number of chars generated

In ten thousand iterations of your code, I was unable to cause a single hash to fail.
$input = [];
for($i = 0; $i < 10000; $i++) {
$input['tmp_password'] = substr(str_shuffle("0123456789"), 0, 4);
$input['password'] = Hash::make($input['tmp_password']);
if(!Hash::check($input['tmp_password'], $input['password'])) {
print "OH SHIT\n";
}
}
Something else is going wrong, in code you haven't shown. As you indicate in the comments, you're doing some other stuff with $user somewhere that's not in your code sample at all.

Related

How would I securely generate a password that contains certain characters?

When creating a password sometimes I need the password to contain uppercase, lowercase, number or a symbol. If I create the password like this it's not guaranteed that each is represented:
$input = 'a..zA..Z0..9$!_'; // generally the whole allowed alphabet
while (strlen($password) < 10) {
$password .= securelyPickRandomCharacterFromString($input);
}
In this case there is a chance that the random process (even though it's safe and completely random) will only select lowercase letters.
I can think of naive approaches like first selecting 1 from each group and then filling the rest randomly. But that would not be cryptographically safe as say random_bytes() is. Maybe shuffle after?
What would be a good and safe algorithm to generate the password containing each "group" of characters.
Note: The password requirements are usually for external system and are out of my control.
Here's a really naive way of doing it (pseudo code):
// Create your lists/arrays of groups
char listLowerCase[] = {'a','b',....};
char listUpperCase[] = {'A','B',....};
char listNums[] = {'1','2',....};
char listSpecialChars[] = {'#','#',...};
// Form a password from those groups (I'm just gonna use length 4 as example)
String pwd = listLowerCase[randomNumber] + listUpperCase[randomNumber]
+ listNums[randomNumber] + listSpecialChars[randomNumber];
// Shuffle the password
String shuffledPwd = shuffle(pwd);
In case you don't want to have the same number of characters from each group, you could try also setting random numbers that determine how many characters you will use in each group. Hope that helped you.
The simplest approach by far is to generate a random password using the chosen alphabet. Then check for constraints such as “must contain at least one of each character class”. If the password doesn't match the constraints, try again in a loop.
do {
$password = '';
while (strlen($password) < 10) {
$password .= securelyPickRandomCharacterFromString($input);
}
} while (!matches_constraints($password));
Within the given constraints on acceptable passwords, this has optimal security, since every acceptable password of the chosen length is equally likely.
In addition to simplicity and security, another benefit of this approach is that it accommodates arbitrary constraints, such as the common “must contain at least 3 of 4 character classes”, without having to write different, complex code for each different constraint.
With any sensible parameters, the number of redraws will be small. For example, a 10-character password generated from non-space printable ASCII characters (94-character alphabet) has a ((94-10)/94)^10 ≈ 0.32 chance of not containing a digit, the smallest of the four character classes. The chance of missing one of the four classes is a little under 0.42. So on average you'll need a little less than 2 iterations to get a suitable password with these particular parameters. Generating random letters is cheap, so performance is not a problem.
You should include protection against nonsensical parameters, for example attempting to generate a 3-character password that contains characters from all 4 classes (which would loop forever), or a 4-character password that contains characters from all 4 classes (which could take a very long time). So add a maximum iteration count.
$iterations = 0;
do {
if ($iterations >= 10) throw new NonsensicalPasswordConstraintException;
$password = '';
while (strlen($password) < 10) {
$password .= securelyPickRandomCharacterFromString($input);
}
++$iterations;
} while (!matches_constraints($password));

Random token generation - a supposedly unlikely collision occurred

A couple months ago, we were using UUIDs to generate random string IDs that needed to be unique across the board. I then changed the algorithm in order to save some data and index space in our database. I tested a few ways to generate unique string IDs, and I decided to use this function:
function generateToken($length) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyz';
$max = strlen($characters) - 1;
$token = '';
for ($i = 0; $i < $length; $i++) {
$token .= $characters[mt_rand(0, $max)];
}
return $token;
}
I'm using this function to generate IDs that are 20 characters long using digits and letters, or you could say these IDs are numbers in base 36. The probability of any 2 IDs colliding should be 1/36^20, but due to the birthday paradox, it can be expected for a collision to occur after about 36^10 records - that's 3.6 quadrillion records. Yet, just a few hours ago a collision occurred, when there were only 5.3 million existing records in the database. Am I extremely unlucky, or my ID-generating function is flawed with respect to randomness? I know mt_rand() isn't truly random, but it is random enough, isn't it?
I would've written a loop that checks if the generated ID is unique and generates a new one if it isn't, but I thought that the chance of getting a collision was so small that the performance cost of such a loop wasn't worth it. I will now include such a loop in the code, but I'm still interested in perfecting the ID generation function if it is indeed flawed.
The implementation of mt_rand() in PHP is rather fluid, so it may differ from one version to the next. However, here are some excerpts from the code used in PHP version 5:
php_rand.h:
/* MT Rand */
#define PHP_MT_RAND_MAX ((long) (0x7FFFFFFF)) /* (1<<31) - 1 */
#ifdef PHP_WIN32
#define GENERATE_SEED() (((long) (sapi_get_request_time(TSRMLS_C) * GetCurrentProcessId())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))
#else
#define GENERATE_SEED() (((long) (sapi_get_request_time(TSRMLS_C) * getpid())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))
#endif
PHPAPI void php_srand(long seed TSRMLS_DC);
PHPAPI long php_rand(TSRMLS_D);
PHPAPI void php_mt_srand(php_uint32 seed TSRMLS_DC);
PHPAPI php_uint32 php_mt_rand(TSRMLS_D);
rand.c:
PHP_FUNCTION(mt_rand)
{
long min;
long max;
long number;
int argc = ZEND_NUM_ARGS();
if (argc != 0) {
if (zend_parse_parameters(argc TSRMLS_CC, "ll", &min, &max) == FAILURE) {
return;
} else if (max < min) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "max(%ld) is smaller than min(%ld)", max, min);
RETURN_FALSE;
}
}
if (!BG(mt_rand_is_seeded)) {
php_mt_srand(GENERATE_SEED() TSRMLS_CC);
}
From the last three lines above, you can see that mt_rand() is automatically seeded the first time it is called. However, the php_mt_srand() function takes an argument of type php_uint32. This means there are only 232 possible seeded states for mt_rand(). So if your script runs roughly 216 times, it is quite likely that mt_rand() will produce the exact same sequence of random numbers.
As suggested by rossum, it would be a much better idea to apply AES encryption to an incrementing 128-bit value. If you base64-encode the encrypted results and discard the trailing ==, then the resulting strings will only be 22 characters long.
Addendum
I left the following script running while I was out this afternoon:
for i in $(seq 1 100000) ; do
php -r 'for ($n=0; $n<32; $n++) echo chr(mt_rand(97,122)); echo chr(10);' >>out
done &
As expected, the first collision occurred after about 216 iterations (which is nowhere near 2616):
$ sort <out | uniq -d
vnexqclzkaluntglgadgwzjnjfsvqfhp
$ grep -n vnexqclzkaluntglgadgwzjnjfsvqfhp out
34417:vnexqclzkaluntglgadgwzjnjfsvqfhp
52159:vnexqclzkaluntglgadgwzjnjfsvqfhp
If you want guaranteed unique 16 byte IDs then I would use encryption. AES uses 16 byte (128 bit) blocks and as long as the inputs are unique the outputs are also guaranteed unique.
Set up AES in ECB mode (which is simpler and faster) and encrypt the numbers 0, 1, 2, 3, 4, ... Your inputs are unique so the outputs will be unique as well.
Crypto sites will tell you that ECB mode has security problems, but those problems only apply if the inputs are not unique. For unique 'random' number generation, as you require, those problems do not apply as your inputs are all unique.

AWS lambda function to speak number as digit in alexa

I have tried to use say-as interpret-as to make Alexa speak number in digits
Example - 9822 must not read in words instead '9,8,2,2'
One of the two ways I have tried is as follows:
this.emit(':tell',"Hi "+clientname+" your "+theIntentConfirmationStatus+" ticket is sent to "+ "<say-as interpret-as='digits'>" + clientno + "</say-as>",'backup');
The other one is this:
this.response.speak("Hi "+clientname+" your "+theIntentConfirmationStatus+" ticket is sent to "+ "<say-as interpret-as='digits'>" + clientno + "</say-as>");
Both are not working but working on a separate fresh function.
Actually your code SHOULD work.
Maybe you can try in test simulator and send us the code your script produces? Or the logs?
I've tried the following:
<speak>
1. The numbers are: <say-as interpret-as="digits">5498</say-as>.
2. The numbers are: <say-as interpret-as="spell-out">5498</say-as>.
3. The numbers are: <say-as interpret-as="characters">5498</say-as>.
4. The numbers are: <prosody rate="x-slow"><say-as interpret-as="digits">5498</say-as></prosody>.
5. The number is: 5498.
</speak>
Digits, Spell-out and Characters all have the effect you want.
If you want to Alexa to say it extra slow, use the prosody in #4.
Try using examples #2 or #3, maybe this works out?
Otherwise the example from Amod will work too.
You can split number into individual digits using sample function ( please test it for your possible inputs-its not tested for all input). You can search for similar function on stackoverflow
function getNumber(tablenumber) {
var number = (""+tablenumber).split("");
var arrayLength = number.length;
var tmp =" ";
for (var i = 0; i < arrayLength; i++) {
var tmp = tmp + myStringArray[i] + ", <break time=\"0.4s\"/> ";
}
return tmp;
}
In your main function... call this
var finalresult = getNumber(clientno);
this.emit(':tell',"Hi "+clientname+" your "+theIntentConfirmationStatus+" ticket is sent to "+ finalresult ,'backup');
Edited: Yep, nightflash's answer is great.
You could also break the numbers up yourself if you need other formatting, such as emphasizing particular digits, add pauses, etc. You would need to use your Lambda code to convert the numeric string to multiple digits separated by spaces and any other formatting you need.
Here's an example based on the answers in this post:
var inputNumber = 12354987;
var output = '';
var sNumber = inputNumber.toString();
for (var i = 0, len = sNumber.length; i < len; i += 1) {
// just adding spaces here, but could be SSML attributes, etc.
output = output + sNumber.charAt(i) + ' ';
}
console.log(output);
This code could be refactored and done many other ways, but I think this is about the easiest to understand.

Random unique string against a blacklist

I want to create a random string of a fixed length (8 chars in my use case) and the generated string has to be case sensitive and unique against a blacklist. I know this sounds like a UUID but I have a specific requirement that prevents me from utilizing them
some characters are disallowed, i.e. I, l and 1 are lookalikes, and O and 0 as well
My initial implementation is solid and solves the task but performs poorly. And by poorly I mean it is doomed to be slower and slower every day.
This is my current implementation I want to optimize:
private function uuid()
{
$chars = 'ABCDEFGHJKLMNPQRSTVUWXYZabcdefghijkmnopqrstvuwxyz23456789';
$uuid = null;
while (true) {
$uuid = substr(str_shuffle($chars), 0, 8);
if (null === DB::table('codes')->select('id')->whereRaw('BINARY uuid = ?', [$uuid])->first())) {
break;
}
}
return $uuid;
}
Please spare me the critique, we live in an agile world and this implementation is functional and is quick to code.
With a small set of data it works beautifully. However if I have 10 million entries in the blacklist and try to create 1000 more it fails flat as it takes 30+ minutes.
A real use case would be to have 10+ million entries in the DB and to attempt to create 20 thousand new unique codes.
I was thinking of pre-seeding all allowed values but this would be insane:
(24+24+8)^8 = 9.6717312e+13
It would be great if the community can point me in the right direction.
Best,
Nikola
Two options:
Just use a hash of something unique, and truncate so it fits in the bandwidth of your identifier. Hashes sometimes collide, so you will still need to check the database and retry if a code is already in use.
s = "This is a string that uniquely identifies voucher #1. Blah blah."
h = hash(s)
guid = truncate(hash)
Generate five of the digits from an incrementing counter and three randomly. A thief will have a worse than 1 in 140,000 chance of guessing a code, depending on your character set.
u = Db.GetIncrementingCounter()
p = Random.GetCharacters(3)
guid = u + p
I ended up modifying the approach: instead of checking for uuid existence on every loop, e.g. 50K DB checks, I now split the generated codes into multiple chunks of 1000 codes and issue an INSERT IGNORE batch query within a transaction.
If the affected rows are as many as the items (1000 in this case) I know there wasn't a collision and I can commit the transaction. Otherwise I need to rollback the chunk and generate another 1000 codes.

Converting an if code into forloop statement

Right now i have to write a code that will print out "*" for each collectedDots, however if it doesn't collect any collectedDots==0 then it print out "". Using too many if statements look messy and i was wandering how you would implement the forloop in this case.
As a general principle the kind of rearrangement you've done here is good. You have found a way to express the rule in a general way rather than as a sequence of special cases. This is much easier to reason about and to check, and it's obviously extensible to cases where you have more than 3 dots.
You probably have made an error in confusing your target number and the iteration value, I assume that collectedDots contains the number of dots you have (as per your if statement) and so you need to introduce a variable to count up to that value
for (int i =0; i <= collectedDots; i++)
{
stars = "*";
System.out.print(stars);
}
Ok, so you already have a variable called collectedDots that is a number which tells you how many stars to print?
So your loop would be something like
for every collected dot
print *
But you can't just print it out, you need to return a string that will be printed out. So it's more like
for every collected dot
add a * to our string
return the string
They key difference between this and your attempt so far is that you were assigning a star to be your string each time through the loop, then at the end of it, you return that string–no matter how many times you assign a star to the string, the string will always just be one star.
You also need a separate variable to keep track of your loop, this should do the trick:
String stars = "";
for(int i = 0; i < collectedDots; i++)
{
stars = stars + "*";
}
return stars;
You are almost correct. Just need to change range limit of looping. Looping initial value is set to 1. So whenever you have collectedDots = 0, it will not go in loop and will return "", as stars is intialized with "" before loop.
String stars = "";
for (int i =1; i <= collectedDots; i++)
{
stars = "*";
System.out.print(stars);
}
return stars;

Resources