-1

I have been using this regexp to verify specific password requirements are met:

$scope.userObj.user_password.match(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*])(?=.{8,})/)

Its been working fine...but I just encountered not one, but two users in the same day who tried to set passwords with period (.) in them. Never occurred to me that users would do that...funny thing about users is they always find ways to do things you never thought of. Anyway, I also thought the period was defined as a normal character and not as a special character...so why isn't the above validating as a good password if a period is used?

Second, obviously the above isn't working so to make it work I need to modify the special symbols part to (I think) the following: (?=.*[!@#\$%\^&\*\.\,\(\)\-\+\=])

In my DB, I encrypt the password with PHP SHA512 and then save that into a standard mysql schar(128) column.

A: Will this suffice for my regexp to properly include periods? The use of periods also makes me wonder if I need to include other standard keyboard symbols like , ( ) - + = etc. (also included in the new regexp).

B: And then, how far down the rabbit hole do you go - is ~ and ` and [, ], {, }, \, | characters that should be considered too? Is there a better way of defining them all without having to list them individually?

C: Considering how I store the password and allowing all these extra special characters...are there any specific issues or security problems I need to be aware of...or things I should avoid?

rolinger
  • 2,787
  • 1
  • 31
  • 53
  • 1
    What's wrong with those two users to have periods in their passwords? You never wanted them to not do so. – revo Jan 24 '19 at 21:52
  • 2
    "I encrypt the password with PHP SHA512". Be aware **SHA512 IS NOT SUITABLE FOR PASSWORDS**. It's a high-speed cryptographic hash meant for things like verifying content. For passwords you **must** use a password-specific hash like [Bcrypt](https://en.wikipedia.org/wiki/Bcrypt) which has variable difficulty and is significantly slower to crack, in many cases deliberately 10,000 times slower than SHA512, or more if the difficulty is cranked up. In PHP use [`password_hash`](http://php.net/manual/en/function.password-hash.php) which uses Bcrypt by default. – tadman Jan 24 '19 at 21:54
  • 1
    You should also be using `VARCHAR(255)` for generic "string" storage. Don't use `CHAR` for anything other than fixed length data where the length is known in advance and is unlikely to change. Examples are limited, but include two-letter ISO country codes. For everything else use `VARCHAR` variable-length fields. – tadman Jan 24 '19 at 21:56
  • **WARNING**: Writing your own access control layer is not easy and there are many opportunities to get it severely wrong. Please, do not write your own authentication system when any modern [development framework](http://codegeekz.com/best-php-frameworks-for-developers/) like [Laravel](http://laravel.com/) comes with a robust [authentication system](https://laravel.com/docs/master/authentication) built-in. At the absolute least follow [recommended security best practices](http://www.phptherightway.com/#security) and **never store passwords as plain-text** or a weak hash like **SHA1 or MD5**. – tadman Jan 24 '19 at 21:56
  • 1
    If you're happy to allow *all* the non-alphanumeric characters, you could just use `[\W_]`. Note that `\W` doesn't include `_` (it's in `\w`) so you have to add that to the set. – Nick Jan 24 '19 at 22:50
  • Keep in mind, that complex password rules will usually not lead to more safe passwords, important is only a minimum length. People cannot remember tons of strong passwords, and such rules can interfere with good password schemes. People can get very inventive to bypass such rules, e.g. by using weak passwords like "Password-2019". Often you end up with weaker passwords instead of stronger ones. – martinstoeckli Jan 25 '19 at 07:28
  • You should give [Reference - Password Validation](https://stackoverflow.com/q/48345922/3600709) a good read. – ctwheels Jun 19 '19 at 14:00

1 Answers1

1

Answer to A: If you test your very first regex (https://www.phpliveregex.com/) you will see that it already accepts periods, because you are including .* after every positive lookahead (?=).

Your regex is efficient to ensure that your input have AT LEAST one lower case AND one upper case AND one special character AND a minimum of eight characters, but it also accepts everything else.

In other words, your regex is a good 'white list', but you have no 'black list'. You should consider making another test to accept just the characters you want

Like: inputValue.replace(/[^a-zA-Z0-9\!\.\#\$\^]/, "");

Answer to B: About what characters you will accept on a password... there is no rule. You are the admin and you can accept whatever you want since you sanitize/escape properly your inputs before parsing and embedding.

If you have a big list of special characters, you will finish with big regexes. But you don't need a big list, it can be as simple as ! . # $ ^

Answer to C: Security issues with user inputs happens when you execute SQL commands or PHP echo, print with a user input without sanitizing/proper escape.

Here is a really good answer about the subject https://stackoverflow.com/a/130323/10677269

Finally, you should consider the comments above. SHA512 is not encryption (it's a digest algorithm) and should not be used to store password in your database unless you 'salt' them (even then, encryption is a better option).

perotta
  • 146
  • 4