Converting from MD5 Legacy Auth System to CakePHP - php

I have a site which runs off an MD5 hashing scheme for passwords. As a way of supporting this legacy system, I've this answer to manually override the login system for now. But this isn't really ideal, as MD5 is pretty much universally known to be awful at encryption. So in the interest of security, what's the best way to migrate users over to the safer CakePHP auth system without causing them undue grief?

Figured it out thanks to this answer (albeit lightly modified). Basically, it updates the user behind the scenes to use the new system if the current system doesn't match up with it.
/**
* Login method
*/
public function login() {
$this->layout = 'homepage';
// If the user is already logged in, redirect to their user page
if($this->Auth->user() != null) {
$this->redirect();
} else {
// If this is being POSTed, check for login information
if($this->request->is('post')) {
if($this->Auth->login($this->loginHelper($this->request->data))) {
// Redirect to origin path, ideally
} else {
$this->Session->setFlash('Invalid username or password, try again');
}
}
}
}
/**
* Update password method
* #param array The user's data array
* #param Returns either a user object if the user is valid or null otherwise
*/
private function loginHelper($data) {
$username = $this->data['User']['username'];
$plainText = $this->data['User']['password'];
$user = current($this->User->findByUsername($username));
$salted = Security::hash($plainText, null, true);
if ($salted === $user['password']) {
return $user; // user exists, password is correct
}
$md5ed = Security::hash($plainText, 'md5', null);
if ($md5ed === $user['password']) {
$this->User->id = $user['id'];
$this->User->saveField('password', $plainText);
return $user; // user exists, password now updated to blowfish
}
return null; // user's password does not exist.
}

Related

PHP-Encrypting login Credentials Accessing API

I am trying to call the Harvest API. But,in order to do that the username and password has to be put in the PHP file. Now, I have security concerns, I don't want to directly put my login credentials in a file. I have read about hashing mechanisms like SHA1, md5. Would that be applicable to my situation? Because most of the examples I am looking right now are based on verifying login credentials. Here, I need a way to hide my login credentials so it is not exposed publicly. Kindly suggest a way to go about this.
$user= //Actual username;
$password= //Actual Password
$harvest_user = $user; // Harvest username, usually an email address
$harvest_pass = $password; // Harvest password
$harvest_account = $account;
require_once 'HarvestAPI.php';
spl_autoload_register(array('HarvestAPI', 'autoload') );
$harvestAPI = new HarvestAPI();
$harvestAPI->setUser($harvest_user);
$harvestAPI->setPassword($harvest_pass);
$harvestAPI->setAccount($harvest_account);
$result = $harvestAPI->getUsers();
// If Harvest returns successful
if ($result->code == 200) {
$people = $result->data;
}
else{
echo "Not Successful";
}
?>
if (!defined('access')): die('no access for you');
class HarvestAPI
{
private $username;
private $...;
public function __construct($u,$...)
{
$this->username = $u;
}
public function start()
{
require_once 'HarvestAPI.php';
spl_autoload_register(array('HarvestAPI', 'autoload') );
$harvestAPI = new HarvestAPI();
$harvestAPI->setUser($this->username);
$harvestAPI->setPassword($....);
$harvestAPI->setAccount($....);
return $harvestAPI->getUsers();
}
}
Usage (in another file):
define('access',0);
require_once 'thatfileabove.php';
$result = (new HarvestAPI('username','ect..'))->start();
($result->code == 200)? $people = $result->data : "Not Successful";
Unless someone looks at your code, its impossible now for them to see your credentials.
You can use the md5() Method.
Just encrypt the password after the registration and store ist in a database or where else you are storing the login information.
At the login just encrypt the typed password an check if its the same like the one in your database.
Nobody can get the password from the database because the md5() Method isn't
reversible.
Encrypt like that: $pw2store = md5($password);
Or replace the password with the encrypted one: $password = md5($password);
Hoped I could help.

PHP Login system hard coded username and password

I had to do a basic login system to protect a page, and I have no access to database so i store the username and password hard coded in php page.
My question is, can this login system hold againts an attack? I need it to hold about 1 month.
Any sugestions to improve will be helpefull.
The code is not in laravel, even if it might look like.
The username and password, will be changed to something stronger of course.
Thank you in advance.
<?php
class UserController {
private $username;
private $password;
private $isLoggedIn = false;
// Credentials
public function credentials() {
$credentials = array(
array(
"username" => "telekom",
"password" => "1234"
),
array(
"username" => "telekom2",
"password" => "1234"
)
);
return $credentials;
}
// Basic login
public function login() {
foreach ($this->credentials() as $credential) {
if ($this->username == $credential['username'] && $this->password == $credential['password']) {
Session::put('username', $this->username);
Session::put('password', $this->password);
$this->isLoggedIn = true;
}
}
}
// Get login status
public function isLoggedIn() {
return $this->isLoggedIn;
}
// Logout
public function logout() {
// Delete all sessions
Session::all();
redirect('/telekom/');
}
// Telekom
public function telekom() {
$form = new Form();
if (Input::get('logout') == 1) {
$this->logout();
}
// Post Data from login form
if (Input::has('username') || Input::has('password')) {
if (!$form->isCsrfValid()) {
$form->errors['CSRF'] = "CSRF Token";
} // CSRF protection is on, comment to disable
if (empty($form->errors)) {
$this->username = Input::get('username');
$this->password = Input::get('password');
// Check Login
$this->login();
if (!$this->isLoggedIn()) {
Session::put('login', 'Username and password do not match.');
} else {
redirect('/telekom/');
}
} else {
Session::put('login', '<p class="color-dark-red"><strong>Errors:</strong></p>
<p>' . $form->displayErrors($form->errors) . '</p>');
}
// Check if session has username and password
} elseif (Session::has('username') && Session::has('password')) {
$this->username = Session::get('username', false);
$this->password = Session::get('password', false);
// Check Login
$this->login();
}
}
}// EOF Class User
// Outside class
$user = new UserController();
// Outside class
if (!$user->isLoggedIn()) {
// display login form
} else {
// display protected content
}
?>
My comments are getting lengthy, so I'll just move them here. I would not recommend you put the username and password in the same file. If PHP ever fails to process the page, it will be dumped as plain text to the user. Even for database connections (where the un/pwd almost have to be stored plain text), most people don't put the information in the same file.
You have a couple options:
Make a separate PHP file that sets your UN/PWD variables, put it somewhere that isn't accessible from outside your server, and include it in index.php. In this case, I wouldn't include the file until right when you're going to compare the variables and let the local scope dump it as soon as possible.
Since this is such basic authentication, you could use Apache's built in password authentication module.
in my opinion, this solution is safe enough when you don't plan to use it forever.
What would I check is setting of your web server - some text editors makes backup copies of edited files, like index.php~, index.php.bkp or so. Make sure whether your web server do not serve those files, if any.
The problem with temporary solutions is that they've never temporary.
Never hard code passwords. Some of the reasons are:
It is harder to keep source code secret than it is a key.
Any vulnerabilities in your site that allow reading of source code may reveal the password.
Passwords from development will end up in production.
It is impossible to change passwords without redeploying.

Codeigniter Ion Auth generating a password

In an app i am making i need to edit and create some passwords with haste and i think i have found a way but i doubt its correctness.
I dug through ion auth and found this function in the ion_auth_model
/**
* Hashes the password to be stored in the database.
*
* #return void
* #author Mathew
**/
public function hash_password($password, $salt=false, $use_sha1_override=FALSE)
{
if (empty($password))
{
return FALSE;
}
//bcrypt
if ($use_sha1_override === FALSE && $this->hash_method == 'bcrypt')
{
return $this->bcrypt->hash($password);
}
if ($this->store_salt && $salt)
{
return sha1($password . $salt);
}
else
{
$salt = $this->salt();
return $salt . substr(sha1($salt . $password), 0, -$this->salt_length);
}
}
and tested by creating this public function in one of my controllers
public function Qpass_gen(){
$pass = $this->ion_auth_model->hash_password('password',FALSE,FALSE);
echo $pass;
}
and when i replaced the Qpass_gen() string with the one stored defaultly in the database by ion_auth,i managed to log in.
Is my method for quickly generating passwords guaranteed to work always?.
Yes, that's a good way to handle it. As the author of the library, that's what I would recommend.

Laravel 4 Auth::attempt returns false on correct values

I have login code that is supposed to work by attempting to authenticate the user using Laravel's Auth::attempt() method. This code works on another site of mine, I have altered it as instead of the Password in the database, it is stored as passwdEncrypted. I cannot change it as the database is in use by another application as well.
The code is below:
// check if in database
$isInDb = User::where('ReferenceCode', $username)->first();
if($isInDb) {
// is in database
// check if password is encrypted yet
if($isInDb->passwdEncrypted) {
// password is encrypted
if(Auth::attempt(array('ReferenceCode' => $username, 'passwdEncrypted' => $password))) {
// authenticated
$array = array();
$array['verified'] = 'true';
$array['type'] = Auth::user()->UserType;
return Response::json($array);
} else {
// not authenticated
$array = array();
$array['verified'] = 'false';
$array['type'] = $type;
return Response::json($array);
}
} else {
// password is not encrypted
// check if plain text password is correct
if($isInDb->Password == $password) {
// plain text password is correct
$hashed = Hash::make($password);
$arr = array('passwdEncrypted' => $hashed);
$updated = User::where('rsmsOnlineUserID', $isInDb->rsmsOnlineUserID)->update($arr);
if($updated) {
$newUser = User::find($isInDb->rsmsOnlineUserID);
echo $newUser->passwdEncrypted;
if(Auth::attempt(array('ReferenceCode' => $username, 'passwdEncrypted' => $password))) {
echo 'logged in';
} else {
dd(DB::getQueryLog());
echo 'could not log in';
}
} else {
echo 'did not update';
}
} else {
// plain text password is incorrect
$array = array();
$array['verified'] = 'false';
$array['type'] = $type;
return Response::json($array);
}
}
} else {
// not in database
return Respone::json(array('success' => 'false'));
}
What is happening: I can't log in, the username and password in the database is 1234, even if I hard code that, it does not work.
It first checks to see if the user is in the database, if it is, it checks to see if there is an encrypted password, if there is not, it will create one from the password given if it matches the plain text password in the database and then log the user in (I have no choice but to have the plain text password stored in the database, that is how they want it).
But it returns the {"verified":"false","type":"prospective_employee"} from the not authenticated part of the code. So neither of the Auth::attempt() blocks work.
I was logging them in manually but even Auth::login() won't work.
I have the following in my User model (with the main database table):
public function getAuthPassword()
{
return $this->Password;
}
/**
* Get the token value for the "remember me" session.
*
* #return string
*/
public function getRememberToken() {
return $this->remember_token;
}
public function setRememberToken($value) {
$this->remember_token = $value;
}
public function getRememberTokenName() {
return 'remember_token';
}
/**
* Get the e-mail address where password reminders are sent.
*
* #return string
*/
public function getReminderEmail()
{
return $this->email;
}
Please note that there is a field in the table called Password, but that is the plain text password, I need to authenticate against the passwdEncrypted field.
You cannot do this with Laravel, and for good reason, but it is ridiciously unsecure and dangerous.
I have no choice but to have the plain text password stored in the
database, that is how they want it
I dont understand - why are you storing BOTH an "unencrypted" and "encrypted" password? There is no point. You should only ever store encrypted passwords. There is no need for any other way, and you need to educate the people as to why.
This code works on another site of mine, I have altered it as instead
of the Password in the database, it is stored as passwdEncrypted. I
cannot change it as the database is in use by another application as
well.
The Laravel Auth code is hard coded to use the "password" column. You cannot simply change it to another colum. That is why your code is failing.
Since you are not using the password column, and since you are not using encrypted passwords, you might as well just create your own unsecure login system, customised to suit your requirements.

Codeigniter users table being compromised

I have a reset password form on my site and I'm unsure whether it's being compromised or if my code is just flakey. The process goes like this:
User enters email address of forgotten password
Password is changed in DB and email is sent to use
User can now login with new password and change once in their account
(I realise this is an imperfect process but it's v1 of the site).
The problem is that intermittently all user passwords are being changed (to the same password) and I can't for the life of me figure it out. XSS and CSRF filters are both enabled inside Codeigniter.
Here's my code:
Controller
$this->form_validation->set_rules('email','Email address','required');
if ($this->form_validation->run() === FALSE)
{
$this->password_reset();
}
else
{
/**
* Generate a new password and send to model
*/
$newpass = substr(md5(rand()),0,10);
$this->users_model->reset_password($newpass);
// stuff for email here
$this->email->send();
/**
* Load view
**/
$data['content'] = 'content/login/reset_done';
$data['title'] = 'Password Reset';
$this->load->view($this->layout, $data);
}
}
Model
public function reset_password($newpass)
{
$email = $this->input->post('email');
$query = $this->db->get_where('users', array('user_email' => $email));
if($query->num_rows())
{
$newpass = do_hash($newpass, 'md5');
$this->db->where('user_email', $email);
$this->db->update('users', array('user_password' => $newpass));
}
}
So to repeat the problem once again: every so often all users passwords are being changed (to the same password). How is this happening?
In your model, don't use $this->input->post, instead send this data as an argument. (Because your model shouldn't act like a controller with routes/sessions/headers/etc information)
It is possible that this happens because $this->input->post('email') is empty or '' (in this case, it will update everybody and num_rows will return the total of users in database), you must check for :
public function reset_password($email, $newpass)
{
if(!$email || !$newpass)
return false;
$query = $this->db->get_where('users', array('user_email' => $email));
if($query->num_rows())
{
$newpass = do_hash($newpass, 'md5');
$this->db->where('user_email', $email);
$this->db->update('users', array('user_password' => $newpass));
}
}
EDIT
- You don't need to do 2 queries (check email then update)
public function reset_password($email, $newpass)
{
if(!$email || !$newpass)
return false;
$newpass = do_hash($newpass, 'md5');
$this->db->where('user_email', $email);
$this->db->update('users', array('user_password' => $newpass));
if ($this->db->affected_rows() < 1) {
return false; //Email wasn't found
} else {
return true;
}
}
You can also call for $this->db->last_query(); to see the query and if the where() did work.
this is not an answer to your specific question, but it needs to be addressed, and it was too long for a comment.
DO NOT use MD5 as a hashing mechanism for passwords. it is outdated, and basically provides zero security anymore. instead use PHPs password_hash() and if you don't have PHP5.5 use the compatibility library. it's very easy to use and works great, and uses better hashing algorithms.
second, it is not generally good practice to create a new password for a user. rather create a token that expires within 1 hour of the request, and then pass that along in the email. then the user enters their email, token, and new password.
and because I can't say it enough, DONT USE MD5

Categories