I am facing a problem that's literally driving me nuts. Following scenario is given:
Application A - Manages the users
pw created using Bcrypt(), cost 14
Application B - fetches the User-Data and stores it inside it's local db
pw verified through bcrypt(), cost 14
Bcrypt implementation via Zend\Crypt\Password\Bcrypt
So, whenever I create a fixed password on App A, synchronize them, authentication on App B works.
However, whenever I create a random password on App A, synchronize them, authentication on App B just won't work.
I pass the password created through a session to a front-end after a redirect.
$password = (string) rand(2938, 9578);
//$password = '12345678';
$bcrypt = new Bcrypt();
$bcrypt->setCost(14);
$entity->setPassword($bcrypt->create($password));
$entityService->save($entity);
$this->flashMessenger()->setNamespace('MpuServerUser')->addSuccessMessage(
"Benutzer-PIN erfolgreich erneuert. PIN: {$password}"
);
return $this->redirect()->toRoute('mpuserveruser');
As you can see that's the part that I'm facing troubles with. Whenever I create a new password for a User with a given string '123456', there are no problems, whatsoever.
But when I use the uncommented part $password = (string) rand(2938, 9578); the password I'm getting on my front-end won't authenticate.
There's no differences between trying with rand() or mt_rand(). Anyone any idea what the heck is going on here? ^^
Update - apparently only passwords that are of 6 chars or longer do work. Even if I set a predefined password of only 4 letters, it won't work.
Here's my piece of code:
(...)
//I USE ZfcUserAdmin MODULE
if ( $this->getOptions()->getCreateUserAutoPassword() ) {
//HERE'S WHERE I'VE TRIED
//\Zend\Math\Rand::getInteger( 2938, 9578 ); --> OK
//rand( 2938, 9578 ); --> OK
$rand = \Zend\Math\Rand::getString( 8 );
$user->setPassword( $rand );
}
$uncrypted_password = $user->getPassword();
$bcrypt = new Bcrypt;
//PASSWORD COST IS SET TO 14, LIKE YOU
$bcrypt->setCost( $userOptions->getPasswordCost() );
$user->setPassword( $bcrypt->create( $uncrypted_password ) );
(...)
The only difference between your solution and mine, is that you redirect and store the password in the session, while I just send an email to the user with the generated password. If I use the new credentials in the email, I can login without problems. Anyway, I think that's not the problem, I suppose it should be something in the BCrypt class.
Related
My old PHP app has a default admin user and md5 encrypted password created by the SQL that creates the database: insert into users values ( 1, 'admin', MD5('changeMe'), 2 );
Is there a simple way to include a default user and encrypted password using PHP's passowrd_hash function on creating the tables? I ask because I understand that password_hash is a native PHP function and I assume it won't be understood in SQL.
The solution to my problem came in three parts. My OP sought a simple way to create a hashed password for the admin user for insertion in the MySQL database on the installation of the application, using the native PHP password_hash() function.
(1) Based on a suggestion by #Nick and #Tadman, I decided to incorporate setting the hash in an installer script that would set not only the hash but other defined site/application variables.
Rather than inserting user values when the database table is created, it was deferred until immediately after, with the admin user entering their credentials in the form that inserts the hash and writes other definitions to a file:
$userpass = $_POST['userpass'];
echo password_hash($userpass, PASSWORD_BCRYPT);
(2) The second part of my problem was replacing all instances of md5()`` withpassword_hash()` and I achieved that by using a neat PHP script I found online to recursively search and replace the occurrences on the server.
Having replaced the md5() occurrences, I needed to change the hash comparison method and again by searching the relevant files I was able to replace instances of:
if ($p != $theUser->pwd ) {
return( false ); }
with:
if(password_verify($p, $theUser->pwd)) {
// Success!
}
else {
// Invalid credentials
echo "Uh oh!";
}
(3) The third step in resolving the problem was discovering that adding $1$ to the opening of the md5 hash could make it readable by password_hash(); so I just needed to make a couple of adjustments in the installed database to the admin user's old password.
Thanks to those who helped shine the light so I could find my way. I'm off now to invent the wheel and sliced bread.
you can do something like this in php:
$hash = password_hash('changeMe');
//echo $hash;
then use this hash in the Database.
My client forgot password to login to the backend of the website that was developed by other developer who refused to help. Therefore, I went to SQL database to see if I could retrieve the password directly from there but it seems that password is encrypted. See below
3a0606b25e75eb6c1fed61886844832e
it would be easier if I knew how the password was encrypted so that I could just encrypt new password and add to SQL but when I looked at the code (in password changing PHP gile) there is something called salt_pass that encrypts the password of this website. See below code :
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$db = new database();
$option_uw = array(
"table" => "users",
"fields" => "password",
"condition" => "id='{$_POST['id']}'"
);
$query_uw = $db->select($option_uw);
$rs_uw = $db->get($query_uw);
if ($rs_uw['password'] == trim(salt_pass($_POST['oldpassword']))) {
$value_pw = array(
"password" => trim(salt_pass($_POST['pass']))
);
$query_pw = $db->update("users", $value_pw, "id='{$_POST['id']}'");
if ($query_pw == TRUE) {
header("location:" . $baseUrl . "/back/user");
}
}else{
$_SESSION[_ss . 'msg_result'] = TRUE;
header("location:" . $baseUrl . "/back/user/changepassword");
}
mysql_close();
}
Here is the salt_pass function
function salt_pass($pass) {
return md5("supapongherb.com" . $pass);
}
Does anybody know how I can regenerate or encrypt the new password according to this code?
PS. the website is developed with MVC programming and I am really capable of it. Please let me know if you would like to see more file.
Thank you in advance!
Let's clear a few things up
but it seems that password is encrypted
First, your password is hashed, not encrypted. There is a difference. Namely that hashes are meant to be one-way. There's no way to look at a hash and just regenerate the password from that.
Second, they're using MD5. They're not actually salting anything, they're appending the same string to all passwords and THEN hashing it. MD5 is a terrible way to hash because it's stupid easy to break. This is the equivalent of securing your front door with a rubber band. It's not secure because you can make millions of guesses a minute. Yes it is that bad.
Third, with the function and the "salt" known, you can easy make a new password this way (via SQL because I'm not guessing what sort of screwy ORM they're using there)
UPDATE users
SET password = MD5(CONCAT('supapongherb.com', 'new_password_here'))
WHERE id = their_user_id_here
Fourth, switch to password_hash. Like now. Get rid of the rubber band and upgrade to a deadbolt, with rabid pitbulls behind it and a shotgun in your lap.
When running two different websites, say free.webhost.com/app1 and free.webhost.com/app2, it seems that Firefox has trouble storing different login credentials for both, especially when the same username is used with different passwords. If a user's credentials on the /app1 site are Name and pass1 and on the other site are Name and pass2, then Firefox can only store one of these and will ask to change the password when hopping between them.
I investigated this problem and to my astonishment this seems to be a WONTFIX in the firefox bug repository: https://bugzilla.mozilla.org/show_bug.cgi?id=263387
Is there any way I can workaround this when designing my apps? Like by setting a certain cookie property in PHP or html, or even specify a (fake) different domain name, so that firefox no longer considers free.webhost.com/app1 and free.webhost.com/app2 as the same website for password storage (and can thus store a different password with the same username for both sites)?
No, there is no workaround or trick for this. Deploy your apps to different domains - even different subdomains (e.g. app1.example.com and app2.example.com) will do.
We need a custom saver. I'm going to try be short and concise.
This is very useful if you don't want the browser saver. I think it can have some applications.
THE BASIC
I suggest in the PHP we use different cookies to save the session with session_name or session.name directive. For each site we must set a session name.
In the HTML we should use different inputs name, so the app1 input will be <input type='email' name='email_app1' /> and app2 email_app2. We also can disable the autocomplete.
The data is saved locally encrypted with AES. For this we can get CryptoJS.
We also want to have salt hash in the client.
THE CONCEPT (summarized):
Save locally the password encrypted. It is returned by the login
controller. Of course if the user wants.
Save a salt which changes in each login. Of course if the user wants.
When the user return to the login page, the JavaScript checks if there
is a salt and it sends it to server. The PHP returns the passphrase and JavaScript decrypts the local password.
the sample code:
In the controller:
// I use functions in the controller like example
public function getLoginPage(){
// it prints the html and js to login using the basics how i have said
}
// salt is sended by the JavaScript
public function getPassphrase( $salt, $username ){
$passPhrase = get_passphrase_from_salt( $salt, $username, Request::IP() );
return $passPhrase;
}
// It is to get the salt
public function getSalt( $username, $password ){
$user = get_user( $username, $password );
// if valid user...
$passphrase = random_string();
$salt = random_string();
$encrypted = encrypt( $password, md5($passphrase) );
save_in_table_salt( $salt, $passphrase, $username, Request::IP() );
// it prints a JSON like example
return json_encode( array( 'salt' => $salt, 'encrypted' => $encrypted) );
}
// ... Normal login etc you could change the salt and reset in the client
In the view we put the JavaScript logic. I used localstorage but I think it's not important.
// in login page
window.onload = function(){
if( localStorage.getItem('salt') !== null ) { // the data is saved
// Get the passphrase
ajax_call('post', 'getPassphrase', {
salt: localStorage.getItem('salt'),
username: localStorage.getItem('username')
}, function( passphrase ){
// It sets the inputs values!
document.getElementById('username_app1').value = localStorage.getItem('username');
document.getElementById('password_app1').value = decrypt( localStorage.getItem('password'), CryptoJS.MD5(passphrase) );
});
}
};
// it captures the submit action
document.getElementById('login_form').onsubmit = function(){
// it asks to user if he wants save locally the credentials
if( localStorage.getItem('salt') === null
&& confirm('Do you want save credentials?') ){
var form = this;
// get salt
ajax_call('post', 'getSalt', {
user: document.getElementById('username_app1').value,
password: document.getElementById('password_app1').value
}, function( object ){
localStorage.setItem('salt', object.salt);
localStorage.setItem('password', object.encrypted);
localStorage.setItem('username', document.getElementById('username_app1').value );
form.submit(); // now yes
});
return false; // it prevents submit
}
};
You must know that the code is a sample. Some functions don't exists and it's only to be understood. We need more conditions and logic to do it works.
UPDATED: Now works with multiple computers and IP security and more!
There is no workaround for this as internal credential storage in Firefox is organized per domain, not per URL.
Even changing Name or ID for input HTML controls or Form tag will not affect this.
Only solution is to host your application on different (sub)domains.
Probably the best solution here would be to create 2 different virtual host for your app.
Like one for webhost.com and one for free.webhost.com.
How To Set Up Apache Virtual Hosts on Ubuntu 12.04 LTS
Hope this help!!
If your are having problem on setting up your virtual host in your server let me know.
Note:You need to create your DNS entry to access the new host you created or you need to add a record to the host file of your system from where you are browsing the site.
I'm trying to create a link that when clicked will login a user automatically and take them to a specific page.
I've thought about creating some sort of hashed string that contains the user's ID, username and a few other pieces of info. When clicked these pieces of information are looked up in the DB and if validated I login them in and redirect them to a specific page.
For sites like Twitter and Facebook when I receive an email notification and click the link in my email I'm automatically taken to my inbox on the corresponding site. I'm trying to duplicate that behavior...
Are there any security issues with doing something like this or is there a safer more preferred way?
if you want to offer this feature to your users, you have to take care of two things:
The validity of the created url must be set in time (ex: 24hours, 48hours).
The created url must only work for one specific user.
(optionnal) The created url only work for one page
I propose this kind of solution to create an url which match these criteria (it's only a proof of concept):
<?php
$privateKey = 'somethingVerySecret';
$userName = 'cedric';
$url = 'my/personal/url';
$timeLimit = new DateTime('Tomorow');
function createToken($privateKey, $url, $userName, $timeLimit){
return hash('sha256', $privateKey.$url.$userName.$timeLimit);
}
function createUrl($privateKey, $url, $userName, $timeLimit){
$hash = createToken($privateKey, $url, $userName, $timeLimit->getTimestamp());
$autoLoginUrl = http_build_query(array(
'name' => $userName,
'timeLimit' => $timeLimit,
'token' => $hash
));
return $url.'?'.$autoLoginUrl;
}
function checkUrl($privateKey){
if((int)$_GET['timeLimit'] > time() ){
return false;
}
//check the user credentials (he exists, he have right on this page)
$hash = createToken($privateKey, $_SERVER['PHP_SELF'], $_GET['name'], $_GET['timeLimit']);
return ($_GET['token'] == $hash);
}
The general standard for logging in is when a user creates an account your program should create a string of seemly random letters and numbers with a certain php function in php 5.5, and then store this in a file with some sort of pointer based on the username. Then when a user tries to login you use that same function and compare the two strings. The function being hash_pbkdf2 even though this php function supports sha... encryptions do not use those. I salt the hash code with the username. Here is an article on all website login and password things. The most secure thing you can do with your website to prevent people from brute force cracking your passwords is to limit the connection speed after a couple wrong password attempt to something so slow it would take longer than the life of the universe to crack after a couple password attempts. If you wanted to make a sort of remember me button store the username in cookies But never the password the browser will take care of the remembering password part if you label your form elements correctly.
I have a user auth table with a few thousand records containing a password field encrypted by bcrypt-ruby. I've ported the app in to PHP / Yii and need to use this field for authentication.
Is there a way to retrieve this Ruby-created field in PHP?
Verification
By "retrieve" I mean that I need to authenticate user logins using a PHP / Yii app to interpret a DB table with a password field created by bcrypt-ruby in a Rails app.
I believe this would solve your problem:
$database_record = "something"; // grab from database
$user_input = 'unicorns'; // take real one from post data
$password = crypt($user_input, '$2a$10$usesomesillystringforsalt$');
// key piece above is the second number, that is the 'work' factor
if (crypt($user_input, $database_record) == $password) {
echo "Password verified!";
}
else {
echo 'failed!'; }
This assumes you stored them using BCrypt::Password.create(desired_pass) in Ruby, and were verifying login by BCrypt::Password.new(database_entry) == form_input.
Additionally, to create a new password in your database (i.e. a new user), store the result of
$password = crypt($user_input, '$2a$10$usesomesillystringforsalt$');
Lastly, make sure that you are always using the correct cost factor. The same password with different cost factors will not be equivalent. The default cost factor in bcrypt-ruby is 10 (current version, 3.0.1).
You should have a look at the crypt functions at PHP.net
Here you should be able to to what you want if you've followed bcrypt correctly in Ruby.