Thread: Password_hash

    #1
  1. A Change of Season
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Mar 2004
    Location
    Nobbies beach, Gold Coast. It's beautiful.
    Posts
    2,575
    Rep Power
    171

    Password_hash


    This has been discussed several times before but I can't find the posts related.

    As the current rule, Password Combat is the way to go. I have got it working fine.

    I want to know about password_hash.

    How is this solution compared to Passowrd Combat and why? Would this be secure enough for a small business (where "bank security" is not neccessary)?
    PHP Code:
    public function crypt_test()
            {
                
    $options = array('cost' => 12'salt' => mcrypt_create_iv(22MCRYPT_DEV_URANDOM),);
                return 
    password_hash('^&UYReePass_Code',PASSWORD_DEFAULT$options);
                
            } 
    Thank you.
  2. #2
  3. --
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Jul 2012
    Posts
    3,921
    Rep Power
    1045
    Hi,

    first of all, congratulations for finally using a library.

    Note that the password_compat library isn't necessary if you have PHP 5.5. In that case, all functions are already built into PHP.

    You shouldn't provide your own salt. Simply let the library take care of that. Your salt isn't wrong, but it's simply not necessary. Just pass the algorithm and the cost factor. You also need to add error checking to make sure the hashing actually worked. Otherwise, you may end up storing an empty string as the password hash.

    Apart from that, your code is OK. bcrypt itself is indeed very secure. But we can't comment on the security of your application without seeing the full code or at least the authentication logic.
    The 6 worst sins of securityHow to (properly) access a MySQL database with PHP

    Why can’t I use certain words like "drop" as part of my Security Question answers?
    There are certain words used by hackers to try to gain access to systems and manipulate data; therefore, the following words are restricted: "select," "delete," "update," "insert," "drop" and "null".
  4. #3
  5. A Change of Season
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Mar 2004
    Location
    Nobbies beach, Gold Coast. It's beautiful.
    Posts
    2,575
    Rep Power
    171
    Originally Posted by Jacques1
    Hi,

    first of all, congratulations for finally using a library.

    Note that the password_compat library isn't necessary if you have PHP 5.5. In that case, all functions are already built into PHP.

    You shouldn't provide your own salt. Simply let the library take care of that. Your salt isn't wrong, but it's simply not necessary. Just pass the algorithm and the cost factor. You also need to add error checking to make sure the hashing actually worked. Otherwise, you may end up storing an empty string as the password hash.

    Apart from that, your code is OK. bcrypt itself is indeed very secure. But we can't comment on the security of your application without seeing the full code or at least the authentication logic.
    Thanks Jacques1;

    While I got you here, I like to tell you I spoke to Codeigniter team, see their reply:
    About Codeigniter's security or other issues: The best way to report those bugs and issues is on the Project Page. Take a look in the issues section to see if someone else has already reported the problem, if not report it yourself.

    CodeIgniter 3.0 is still being worked on by the community, but there have been some snags along the way. Hopefully it'll be out soon, but I can't say when that will be.
    It seems like they are willing to fix issues. Maybe if you have sometime post your suggestions about their security
  6. #4
  7. A Change of Season
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Mar 2004
    Location
    Nobbies beach, Gold Coast. It's beautiful.
    Posts
    2,575
    Rep Power
    171
    Jacques1;

    Need help, missing the point. I notice each time I generate the password it gives me a different value:
    PHP Code:
    echo password_hash($password,PASSWORD_DEFAULT);
    echo 
    "<hr />";
    echo 
    password_hash($password,PASSWORD_DEFAULT); 
    prints
    $2y$10$Dz03P9Aq9fY8DyhJv2ZNSOrQzRVPdUfGNlj0LdO2aWu5kzbL7oZrC
    <hr />
    $2y$10$rgkpmZ89d4TD8mEWBMlOIuxpgpCOqFJQ2JCe8VDfVKLHTvBaSIytW
    As you can see it creates 2 different values for the same string. How can I authenticate now? For example when user wants to log in if they select the same password the result would be different. This means this code never says valid password:
    PHP Code:
    echo $hashed password_hash($password,PASSWORD_DEFAULT);
                echo 
    "<hr />";
                if (
    password_verify('$password'$hashed))
                    {
                        echo 
    'Password is valid!';
                    }
                else
                    {
                        echo 
    'Invalid password.';
                    } 
    Thanks
  8. #5
  9. --
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Jul 2012
    Posts
    3,921
    Rep Power
    1045
    Generating different hashes for the same password is one of the key features of modern password hashing algorithms. It has to be like that. Otherwise, attackers could brute-force all hashes at the same time or even use precomputed tables. That's one of the reasons why plain MD5 is so insecure.

    When you hash a new plaintext password, bcrypt generates a long random string (the salt) and then calculates the hash based on the password, the cost factor and the salt. Those parameters are stored in the resulting hash string:

    Code:
    $2y$10$Dz03P9Aq9fY8DyhJv2ZNSOrQzRVPdUfGNlj0LdO2aWu5kzbL7oZrC
    
    means:
    
    $
    2y -> an algorithm identifier; "2y" stands for "bcrypt with bugfix"
    $
    10 -> the cost factor
    $
    Dz03P9Aq9fY8DyhJv2ZNSO -> 22 digits for the encoded salt
    rQzRVPdUfGNlj0LdO2aWu5kzbL7oZrC -> 31 digits for the actual hash
    To verify a password against a given hash, bcrypt extracts the cost factor and salt from the hash and uses it to hash the password with the same parameters as before. If the result is the same, the passwords are the same.

    If the verification doesn't work in your case, there's some other issue. Try this code:

    PHP Code:
    <?php

    $password 
    'foo';

    $hash password_hash($passwordPASSWORD_DEFAULT, array('cost' => 12));
    echo 
    'Hash:<br>';
    var_dump($hash);
    echo 
    '<br>';

    echo 
    'Verify:<br>';
    echo 
    password_verify($password$hash) ? 'Success' 'Failure';
    The 6 worst sins of securityHow to (properly) access a MySQL database with PHP

    Why can’t I use certain words like "drop" as part of my Security Question answers?
    There are certain words used by hackers to try to gain access to systems and manipulate data; therefore, the following words are restricted: "select," "delete," "update," "insert," "drop" and "null".
  10. #6
  11. --
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Jul 2012
    Posts
    3,921
    Rep Power
    1045
    Regarding Code Igniter:

    The problem is that their overall security approach is wrong. It's not a matter of a few bugs here and there. They would have to throw away a large part of the security-related code, change several features, break backwards compatibility and explain this to their users. The current CI team doesn't seem to be willing to take this step.

    For example, many people have already pointed out that the XSS filter is conceptually wrong. Yet the CI developers keep using it and merely patch it whenever somebody has found yet another way to bypass the filter.

    As long as that's the case, it's simply pointless to make suggestions. If you want security, you'll have to use another framework.
    The 6 worst sins of securityHow to (properly) access a MySQL database with PHP

    Why can’t I use certain words like "drop" as part of my Security Question answers?
    There are certain words used by hackers to try to gain access to systems and manipulate data; therefore, the following words are restricted: "select," "delete," "update," "insert," "drop" and "null".
  12. #7
  13. A Change of Season
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Mar 2004
    Location
    Nobbies beach, Gold Coast. It's beautiful.
    Posts
    2,575
    Rep Power
    171
    Ok. Something like this should work too then:
    PHP Code:
    public function crypt_password($posted_password$hash)
            {
                if(
    password_verify($posted_password,$hash))
                    {    
                        return 
    TRUE;
                    }
                else
                    {
                        return 
    FALSE;
                    }    
            }




    if(
    $this->crypt_password($this->input->post('password'),$data['member_details'][0]->password))
                    {
                        
    $newdata = array('member_id'  => $data['member_details'][0]->id'logged_in' => TRUE);
                        
    $this->session->set_userdata('logged_data'$newdata);
                        
    redirect(site_url('profile'), 'location'301);
                        
                    } 
    Comments? Hit me, hit me hard.
  14. #8
  15. --
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Jul 2012
    Posts
    3,921
    Rep Power
    1045
    The return value of crypt_password() already is either true or false. It doesn't get "truer" or "falser" by putting it into an if statement. Simply return the value.

    The method name "crypt_password" is also rather weird. How does that explain the purpose of the method?

    And the 301 HTTP code is wrong. This is a permanent redirect, so the user won't be able to visit the current page again until the browser cache has been cleared. You want a temporary redirect, which is 303 (or the old 302).
    The 6 worst sins of securityHow to (properly) access a MySQL database with PHP

    Why can’t I use certain words like "drop" as part of my Security Question answers?
    There are certain words used by hackers to try to gain access to systems and manipulate data; therefore, the following words are restricted: "select," "delete," "update," "insert," "drop" and "null".
  16. #9
  17. A Change of Season
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Mar 2004
    Location
    Nobbies beach, Gold Coast. It's beautiful.
    Posts
    2,575
    Rep Power
    171
    Originally Posted by Jacques1
    The return value of crypt_password() already is either true or false. It doesn't get "truer" or "falser" by putting it into an if statement. Simply return the value.

    The method name "crypt_password" is also rather weird. How does that explain the purpose of the method?

    And the 301 HTTP code is wrong. This is a permanent redirect, so the user won't be able to visit the current page again until the browser cache has been cleared. You want a temporary redirect, which is 303 (or the old 302).
    About truer or falser, you have told me that before as well but the reason I do this is that I call this funciton from elsewhere. Perhaps if you see my whole controller it makes sense to you and you realise what I am missing
    PHP Code:
    <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

    class 
    Log_in extends CI_Controller {
        
        public function 
    index()
            {
                
                
    $this->load->library('header');
                
    $this->header->index();
                
    $this->load->view('header_view');
                
    $this->load->view('login_view');

            }
        
        public function 
    crypt_password($posted_password$hash)
            {
                if(
    password_verify($posted_password,$hash))
                    {    
                        return 
    TRUE;
                    }
                else
                    {
                        return 
    FALSE;
                    }    
            }    
        public function 
    check()
            {
                
    $this->load->library('header');
                
    $this->header->index();
                
                
                
    $this->load->library('form_validation');
                
    $this->form_validation->set_error_delimiters('<div class="error">''</div>');
                
    $this->form_validation->set_rules('username''Username''required|callback_username_check');
                
    $this->form_validation->set_rules('password''Password''required');
                if (
    $this->form_validation->run() == FALSE)
                    {
                        
    $this->load->library('header');
                        
    $this->header->index();
                        
    $this->load->view('header_view');
                        
    $this->load->view('login_view');
                    }
                else
                    {
                        
                    }
                
                        
            }

            public function 
    username_check($str)
            {
                
    $this->load->model('model_auth');
                if(
    $this->model_auth->check_credentials($this->input->post('username')))
                {
                    
    $data['member_details'] = $this->model_auth->check_credentials($this->input->post('username'));
                    if(
    $this->crypt_password($this->input->post('password'),$data['member_details'][0]->password))
                    {
                        
    $newdata = array('member_id'  => $data['member_details'][0]->id'logged_in' => TRUE);
                        
    $this->session->set_userdata('logged_data'$newdata);
                        
    redirect(site_url('welcome'), 'location'301);
                    }
                    else
                    {
                        
    $this->form_validation->set_message('username_check''Invalid login details');
                        return 
    FALSE;
                    }
                }
                else
                {
                    
    $this->form_validation->set_message('username_check''Invalid login details');
                    return 
    FALSE;
                }
            }    
    }
    Originally Posted by Jacques1
    And the 301 HTTP code is wrong. This is a permanent redirect, so the user won't be able to visit the current page again until the browser cache has been cleared.
    I am not sure what you mean.
    redirect() does a "header redirect" to the URI specified. If you specify the full site URL that link will be build, but for local links simply providing the URI segments to the controller you want to direct to will create the link. The function will build the URL based on your config file values.

    The optional second parameter allows you to choose between the "location" method (default) or the "refresh" method. Location is faster, but on Windows servers it can sometimes be a problem. The optional third parameter allows you to send a specific HTTP Response Code - this could be used for example to create 301 redirects for search engine purposes. The default Response Code is 302. The third parameter is only available with 'location' redirects, and not 'refresh'. Examples:
    if ($logged_in == FALSE)
    {
    redirect('/login/form/', 'refresh');
    }

    // with 301 redirect
    redirect('/article/13', 'location', 301);
  18. #10
  19. --
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Jul 2012
    Posts
    3,921
    Rep Power
    1045
    Originally Posted by English Breakfast Tea
    About truer or falser, you have told me that before as well but the reason I do this is that I call this funciton from elsewhere. Perhaps if you see my whole controller it makes sense to you and you realise what I am missing
    You generally seem to have trouble working with booleans.

    A boolean value is a normal value just like an integer, a string or whatever. When a function returns a boolean, you can simply use it. You do not have to put it into an if statement. Why should you? How is your if statement different from simply returning the value of password_verify()? All you do is add 7 useless lines.

    A few lines after that, you have this:

    PHP Code:
    if ($this->form_validation->run() == FALSE) ... 
    Again: The return value of $this->form_validation->run() already is either true or false. It's a real, actual value. You can simply use it, no need for any extra stuff:

    PHP Code:
    if (!$this->form_validation->run()) ... 


    Originally Posted by English Breakfast Tea
    I am not sure what you mean.
    When you send a 301 status code, you tell the browser that the current URL is obsolete and should always be replaced with the target URL. The browser will cache this and always go to the target URL when you enter the original URL. Try it.

    In your case, this is totally wrong, because you do not want to permantently replace the login URL with the profile URL. You just wanna redirect the user to the profile page. This is a temporary redirect (status code 303 or 302).

    I'm actually surprised that you haven't noticed this bug yet. In your current application, you can never go through the login procedure again once you've logged in, no matter how often you log out. It only works after clearing the browser cache.
    Last edited by Jacques1; December 26th, 2013 at 12:28 AM.
    The 6 worst sins of securityHow to (properly) access a MySQL database with PHP

    Why can’t I use certain words like "drop" as part of my Security Question answers?
    There are certain words used by hackers to try to gain access to systems and manipulate data; therefore, the following words are restricted: "select," "delete," "update," "insert," "drop" and "null".
  20. #11
  21. A Change of Season
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Mar 2004
    Location
    Nobbies beach, Gold Coast. It's beautiful.
    Posts
    2,575
    Rep Power
    171
    Originally Posted by Jacques1
    A few lines after that, you have this:

    PHP Code:
    if ($this->form_validation->run() == FALSE) ... 
    Again: The return value of $this->form_validation->run() already is either true or false. It's a real, actual value. You can simply use it, no need for any extra stuff:

    PHP Code:
    if (!$this->form_validation->run()) ... 
    This code is directly from Codeigniter's manual.
    PHP Code:
    class Form extends CI_Controller {

        function 
    index()
        {
            
    $this->load->helper(array('form''url'));

            
    $this->load->library('form_validation');

            if (
    $this->form_validation->run() == FALSE)
            {
                
    $this->load->view('myform');
            }
            else
            {
                
    $this->load->view('formsuccess');
            }
        }

    Last edited by English Breakfast Tea; April 15th, 2014 at 08:29 AM.
  22. #12
  23. Devshed Beginner (1000 - 1499 posts)

    Join Date
    Jan 2004
    Location
    New Springfield, OH
    Posts
    1,181
    Rep Power
    1469
    Originally Posted by English Breakfast Tea
    This code is directly from Codeigniter's manual.
    ...and that says a lot.
    Don't like me? Click it.

    Scripting problems? Windows questions? Ask the Windows Guru!

    Stay up to date with all of my latest content. Follow me on Twitter!

    Help us help you! Post your exact error message with these easy tips!
  24. #13
  25. --
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Jul 2012
    Posts
    3,921
    Rep Power
    1045
    Yes, it shows that the author doesn't understand the PHP type system, which isn't necessarily a good thing when you write the manual for a framework.

    If you want to check strictly for false, you need the === operator:

    PHP Code:
    $this->form_validation->run() === false 
    This is true if and only if the expression on the left is exactly false. Otherwise, the expression evaluates to false.

    If the left expression is already guaranteed to yield a boolean (like in this case), or if you want to do a “sloppy” check for all falsy values (false, null, 0, 0.0 etc.), you simply use the negation operator:

    PHP Code:
    !$this->form_validation->run() 
    But == in conjunction with a boolean is nonsense. It doesn't do what it seems to do, and it's too cumbersome for what it does.

    Whenever you see somebody use this, you know they lack basic PHP knowledge.
    The 6 worst sins of securityHow to (properly) access a MySQL database with PHP

    Why can’t I use certain words like "drop" as part of my Security Question answers?
    There are certain words used by hackers to try to gain access to systems and manipulate data; therefore, the following words are restricted: "select," "delete," "update," "insert," "drop" and "null".

IMN logo majestic logo threadwatch logo seochat tools logo