Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

regex elegance contest - validate a pw

by tos (Deacon)
on Feb 11, 2004 at 10:05 UTC ( [id://328207]=perlquestion: print w/replies, xml ) Need Help??

tos has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,

a colleague of mine came to me with a question on a special regex which has to decide whether a given pw is valid or not. The pw has to suffice the following restrictions:

  • it's length has to be within 5-8 chars
  • at least one lower-char, one upper-char and one number has to occur

I agreed to him that this requirement isn't trivial. But on the other side I told him that i could imagine a really short solution. Perhaps i leaned out of the window a bit too wide, because after a little fiddling i got this:

#!/usr/bin/perl -w # vim: set tabstop=3 use strict; while (<DATA>) { chomp; print "\n$_\n"; length() < 5 && do { print "too short\n"; next }; length() > 8 && do { print "too long\n"; next }; m# ^ \w*[a-z]\w*[A-Z]\w*[0-9]\w*| \w*[a-z]\w*[0-9]\w*[A-Z]\w*| \w*[A-Z]\w*[a-z]\w*[0-9]\w*| \w*[A-Z]\w*[0-9]\w*[a-z]\w*| \w*[0-9]\w*[A-Z]\w*[a-z]\w*| \w*[0-9]\w*[a-z]\w*[A-Z]\w* $ #x ? print "valid\n" : print "invalid (Input must have at least one lowercase-, " . "one uppercase-Char and one Number! (f.i.: \'12Three +\')\n"; } __DATA__ 1245Za78 1245Za7b8 45a7b8 a78Z 12Three kMdlOz 6KYX diImMU1Y ZNw4uWSht jDqvSN qVRR le2WTQv us1j3SerC OZv0LtSJ 9qyscg LbX7o74 80TeRHq 7YIiXnEV8 e1Yctl9 8iGoc R87MeDCFz ziTnlk cziP

This solution is quite good but appears a little bulky to me. Especially a more compact regex would be nice. Perhaps the length-validation could be made within the regex too.

I wonder who has THE solution which combines shortness and elegance in a tremendous way ;)

regards, tos

janitored by ybiC: Balanced <readmore> tags, minor format cleanup for legibility

Replies are listed 'Best First'.
Re: regex elegance contest - validate a pw
by kvale (Monsignor) on Feb 11, 2004 at 10:23 UTC
    Here is the test in a single rexexp:
    #!/usr/bin/perl -w use strict; while (<DATA>) { chomp; print "\n$_\n"; /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{6,9}$/ ? print "valid\n" : print "invalid (Input must have at least one lowercase-, " . "one uppercase-Char and one Number! (f.i.: \'12Three\')\ +n"; } __DATA__ 1245Za78 1245Za7b8 45a7b8 a78Z 12Three kMdlOz 6KYX diImMU1Y ZNw4uWSht jDqvSN qVRR le2WTQv us1j3SerC OZv0LtSJ 9qyscg LbX7o74 80TeRHq 7YIiXnEV8 e1Yctl9 8iGoc R87MeDCFz ziTnlk cziP

    -Mark

Re: regex elegance contest - validate a pw
by grinder (Bishop) on Feb 11, 2004 at 11:04 UTC
    I wonder who has THE solution which combines shortness and elegance in a tremendous way

    You do realise that it is not always possible to reconcile these two aims?

    A single "one size fits all" test will not give you the chance of reporting why the password is no good. If this is not a problem, then my best shot looks like:

    #! /usr/local/bin/perl -w use strict; while( <DATA> ) { chomp; my $ok = ( length $_ >= 5 and length $_ <=8 and /\d/ and /[A-Z]/ and /[a-z]/ ); print sprintf('%-12s', $_), ($ok ? 'valid' : 'invalid '), "\n"; }

    I would probably break it up into separate test as shown elsewhere in this thread. You might also want to avoid reinventing the wheel and look at Data::Password::BasicCheck. Also, given that most people never bother to change the password they are given, you should also investigate Crypt::GeneratePassword.

Re: regex elegance contest - validate a pw
by Anonymous Monk on Feb 11, 2004 at 10:22 UTC
    KISS. A single regex would not be clever
    while (<DATA>) { chomp; print "\n$_\n"; if ( length() < 5 ) { print "too short\n" } elsif ( length() > 8 ) { print "too long\n" } elsif ( not /\d/ ) { print "need at least one digit\n" } elsif ( not /[a-z]/ ) { print "need at least one lowercase letter\n" } elsif ( not /[A-Z]/ ) { print "need at least one uppercase letter\n" } }
Re: regex elegance contest - validate a pw
by Abigail-II (Bishop) on Feb 11, 2004 at 10:55 UTC
    Solutions have already been presented, but note that your solution checks for more restrictive passwords than your requirements. Your regex disallows for instance 1d!Ot, which isn't disallowed by your requirements.

    Abigail

Re: regex elegance contest - validate a pw
by Roger (Parson) on Feb 11, 2004 at 10:42 UTC
    Ah, kvale has beaten me to the regex solution. Ok, I will post a slightly different one...
    #!/usr/bin/perl -w # vim: set tabstop=3 use strict; while (<DATA>) { chomp; print "$_ .. "; if (m/^((?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9]).*)$ (??{ ! exists %{{qw! 5 0 6 0 7 0 8 0 !}}->{length($1)} })/x) { print "valid\n" } else { print "invalid\n" } } __DATA__ 1245Za78 1245Za7b8 45a7b8 a78Z 12Three kMdlOz 6KYX diImMU1Y ZNw4uWSht jDqvSN qVRR le2WTQv us1j3SerC OZv0LtSJ 9qyscg LbX7o74 80TeRHq 7YIiXnEV8 e1Yctl9 8iGoc R87MeDCFz ziTnlk cziP
Re: regex elegance contest - validate a pw
by EvdB (Deacon) on Feb 11, 2004 at 12:03 UTC
    One immediate reaction is that if you are after secure passwords and provide an example then you will need to add this to your code:
    if ( $password eq '12Three' ) { warn "ALERT: unimaginative user detected, take evasive action"; }

    --tidiness is the memory loss of environmental mnemonics

Re: regex elegance contest - validate a pw
by fletcher_the_dog (Friar) on Feb 11, 2004 at 15:33 UTC
    sub valid{ local $_ = shift; return /\d/ && /[a-z]/ && /[A-Z]/ && /^.{5,8}$/ }
Re: regex elegance contest - validate a pw
by CountZero (Bishop) on Feb 11, 2004 at 16:16 UTC
    Contrary to what many people believe, putting such (arbitrary) conditions on the format of passwords actually makes it easier to crack them.

    If you require the passwords to be at least 5 characters wide, you have decreased the number of possible passwords by approx. 63**4 (almost 16 million), i.e. all paswords with 4 or less characters of the range a-z A-Z 0-9 and "empty".

    Requiring at least one lower case character further reduces the password-space by 59% (37/63, i.e. none of A-Z 0-9 and "empty" are allowed in that position), id. for the required upper case character, and asking for at least one number finally lowers the total number of possible passwords by another 84% (53/63 - none of a-z A-Z and empty are allowed). In total the combination of these three conditions shrinks the number of allowed passwords to about one third of what was possible without these restrictions.

    My calculations may be a bit off as I did not take into acount the position of the restricted characters, but by and large it will be OK.
    There will still be a large number of possible passwords (which will probably defeat a brute force attack), but why limit the password-space, esp. since these rules do not guarantee "good" passwords at all? A typical birthday "8Jun1959" is a good password, whereas all say that one should avoid such easy to guess passwords.

    The only good password is therefore one which is randomly generated.

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

      "The only good password is therefore one which is randomly generated."

      Such passwords are extremely hard to guess, but there's a weakness: Giving out random passwords is just asking for people to write those hard-to-remember passwords down on Post-it(TM) notes. If someone sneaks into the office and finds a few written down passwords, the need to guess is eliminated completely.
        All too true, but you don't even need to look at your co-workers Post-It™ notes. Internet Explorer will remember your passwords for you! (and allow anyone in)

        CountZero

        "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

      Contrary to what many people believe, putting such (arbitrary) conditions on the format of passwords actually makes it easier to crack them.

      I suppose technically you are reducing the keyspace an attacker would need to attack the gain all passwords. The goal of something like this though isn't to try and make individual passwords harder to crack, but to limit the amount of passwords and attacker can gain easily (He's not going to try the entire keyspace regardless, it's to big). You want to limit the effectiveness of dictionary attackers, where an attacker can gain 80% of your password list in half an hour because all your users use common words as their passwords.
        Yes I understand that, but the artificial --IMHO-- restrictions do not guarantee that common words are excluded as probably most users will still use a common word, capitalize the first character and add a number at the end; or use their birthday or anything equally silly.

        CountZero

        "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Re: regex elegance contest - validate a pw
by leriksen (Curate) on Feb 12, 2004 at 07:45 UTC
    Your test data haven't considered that \w also matches '_' , so this is an allowed character in your passwords - is that what you want ?

    From perlre

    In addition, Perl defines the following: \w Match a "word" character (alphanumeric plus "_")

    +++++++++++++++++
    #!/usr/bin/perl
    use warnings;use strict;use brain;

      Well, isn't \w also locale aware?
      Example: (Germany)

      % perl -e 'use locale; $_=q{äöü}; print qq{Locale aware!\n} if /^\w+$/ +;'

      Results in:
      Locale aware!

      Thus, \w is bad when you really mean /[A-Za-z0-9]/. On the other hand, using the latter character class instead of \w is usually more of a problem for most applications. The best example is, I daresay, entering my last name in some form on the web that does this: Müller ;-)

      Steffen

        I think it is also Unicode aware in 5.8+ so that introduces all sorts of variation - if Unicode is supported, \w usually refers to all alphanumberics - in fact you might see \w start to die out and things like unicode properties appear

        $word = m/([\p{Letter}\p{Number}]+)/;

        I think that is correct...

        I know that in Java's regex package, \w == \A-Za-z0-9_\ only

        I got most of this info from Friedl's Mastering Regular Expressions - if you dont own it - buy it and read it from chapters 1-7 - it is truely excellent, a standout book.

        +++++++++++++++++
        #!/usr/bin/perl
        use warnings;use strict;use brain;

Re: regex elegance contest - validate a pw
by jsalvata (Initiate) on Feb 18, 2004 at 00:01 UTC

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://328207]
Approved by b10m
Front-paged by gmax
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (2)
As of 2024-04-26 02:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found