
  /////////////////////////////// Updated Post Below ////////////////////////////


This question has received a lot of hits, more than I ever thought it would have on such a basic topic. So, I thought I would update people on what I am doing. Also I keep reading in the comments that I am storing passwords as plain text. Just to clarify I am not. 

My updated validation function : 

public function is_password($str) {
        if (strlen($str) < 10) { // Less then 10
            $this -> set_message('is_password', 'Password must include at least one number, one letter, one capital letter , one symbol and be between 10 and 100 characters long.');
            return FALSE;
        } elseif (strlen($str) > 100) { // Greater then 100
            $this -> set_message('is_password', 'Password must include at least one number, one letter, one capital letter , one symbol and be between 10 and 100 characters long.');
            return FALSE;
        } elseif (!preg_match("#[0-9]+#", $str)) { // At least 1 number
            $this -> set_message('is_password', 'Password must include at least one number, one letter, one capital letter , one symbol and be between 10 and 100 characters long.');
            return FALSE;
        } elseif (!preg_match("#[a-z]+#", $str)) { // At least 1 letter
            $this -> set_message('is_password', 'Password must include at least one number, one letter, one capital letter , one symbol and be between 10 and 100 characters long.');
            return FALSE;
        } elseif (!preg_match("#[A-Z]+#", $str)) { // At least 1 capital
            $this -> set_message('is_password', 'Password must include at least one number, one letter, one capital letter , one symbol and be between 10 and 100 characters long.');
            return FALSE;
        } elseif (!preg_match("#\W+#", $str)) { // At least 1 symbol
            $this -> set_message('is_password', 'Password must include at least one number, one letter, one capital letter , one symbol and be between 10 and 100 characters long.');
            return FALSE;
        } else {
            return TRUE; // No errors
        }     
    }


Each time it returns FALSE, I always tell them the entire password need. 

Just to answer some of the questions as to why it is so long : 

Why not so long? People at my job that I talk to use sentences. Very long ones at that.

How am I hashing my passwords? / Why use 100 characters? ->  just use better hashing algorithm

For PHP, I am using the best there is for this language. I am using this library which is the PHP 5.5 equivalence of the new password hashing API created by Anthony Ferrara. My reasoning for this hashing use is simple, very high demand on the CPU (if you ever test it out on a Linux/Windows box CPU usage is at 100%). Also, the algorithm is very scalable due to the cost factor the higher the cost the more grueling the task is for the CPU to log a person in. Last I "Tested", I put the cost to 24. An entire hour passed for me to try and login and I got a PHP time out error before I even got past the login screen (this was a foolish cost factor). A study done by Jeremi Gosney (THIS IS THE PDF DOWNLOAD OF THE REPORT) which tested the strength of this function compared to other more popular ones (yes, more popular) concluded that even with 25 - GPUs, while using bcrypt at a cost of 5, password hashing is the last of your concerns. I use a cost of 17...

My function if any one is interested (The parts that pertain to this subject at least) :

public function create_user($value) {
        $this -> CI = get_instance();
        $this -> CI -> load -> library('bcrypt');

        foreach ($value as $k => $v) {// add PDO place holder to the keys
            $vals[":$k"] = $v;
        }
        $vals[":password"] = $this -> CI -> bcrypt -> password_hash($vals[":password"], PASSWORD_BCRYPT, array("cost" => 17)); // Take old $vals[":password"] and run it through bcrypt to come up with the new $vals[":password"] 


Hopefully this question helps others out there.


  /////////////////////////////// Original Post Below ////////////////////////////


I'm currently working on a new project, and an issue struck me. 

Is it it safe to disclose your password requirements? If so, why is it safe?

I have a function that does validation on a password and each step shows the user why validation does not work. 

Here is my function: 

public function is_password($str) {
    if (strlen($str) < 10) {
        $this -> set_message('is_password', 'Password too short.');
        return FALSE;
    } elseif (strlen($str) > 100) {
        $this -> set_message('is_password', 'Password is too long.');
        return FALSE;
    } elseif (!preg_match("#[0-9]+#", $str)) {
        $this -> set_message('is_password', 'Password must include at least one number.');
        return FALSE;
    } elseif (!preg_match("#[a-z]+#", $str)) {
        $this -> set_message('is_password', 'Password must contain at least one letter.');
        return FALSE;
    } elseif (!preg_match("#[A-Z]+#", $str)) {
        $this -> set_message('is_password', 'Password must contain at least one capital letter.');
        return FALSE;
    } elseif (!preg_match("#\W+#", $pwd)) {
        $this -> set_message('is_password', 'Password must include at least one symbol.');
        return FALSE;
    } else {
        return TRUE;
    }
}


My thought on this is, if we let the "user" / attacker know what my passwords consist of wouldn't it be easier for the attacker to know? I know security through obscurity is not a best practice, but could it be a strong argument in this situation?

I would like to know if I am going about this in the right way. Any help would be great.

If you do not divulge your "password requirements" then your users will hate you. Some will not succeed in finding an "acceptable password" and will call the helpdesk. Or, worse, if the users are customers then they will go buy elsewhere. A great way to kill your own business !

On the other hand, if divulging your "password requirements" really help attackers in a non-negligible way, then your password requirements are awfully bad: not only do they antagonize users, but they also restrain the users into a too small set of possible passwords.

Note that attackers can usually guess quite well what your "password requirements" are, e.g. by trying to register themselves.

In any case, "password requirements" are counter-productive and decrease security, save for a "minimum length" which can be rationally justified. So just don't do that. Key to password security is user education, possibly helped with some tools (e.g. a random generator for strong passwords). Enforcing constraints does not help; and enforcing hidden constraints is just worse. For instance, if your rules call for at least one digit and one symbol, then a surprisingly high proportion of users will just append "1." at the end of their password; attackers know that. The extra suffix will not add much to the password entropy (i.e. the number of potential passwords the attacker has to try for a successful break) but will use up some of the scarce resource known as "user patience": users will prefer shorter passwords, since they have to add the "1." suffix to appease your server.
