I found myself recently writing a script to do user account management tasks in an environment with multiple NIS, LDAP, and Active Directory directories. Along the way, I found myself in need of a way to generate a password that was reasonably secure by fitting the requirements of our password policy. The policy we have is fairly common, since it basically is what Active Directory does when the password complexity rules are turned on.
"Great," I thought to myself. "I can just use a module from CPAN!"
There turned out to be a few, so off I went to install them and give them a try. The first thing I noticed is that they all seemed to work fairly well at doing a good bit more than I really needed. The problem however was that none of them seemed to be configurable to exactly match our password complexity requirements.
"Well, crap! I guess I'll have to write my own."
So off I went to do just that. What astonished me, was just how simple it was to write something that managed it.
use strict;
use warnings;
use List::Util qw(shuffle);
sub gen_password {
my $password;
my $minlength = 8;
my $maxlength = 12;
my $minclasses = 3;
my $other = rand($maxlength-$minlength) + $minlength - $mincl
+asses;
my @classes = (
['a' .. 'z'],
['A' .. 'Z'],
[0 .. 9],
[qw( . ! / \ - : ; " ' ? $ ^ & @ [ ] = + | < > % * ~ )
+ , qw/ ( ) /, ',', '#'],
);
my @required = shuffle(0 .. $#classes);
my @indexes = shuffle(@required[ map { rand @required } (1 ..
+$other) ], @required[0 .. ($minclasses - 1)]);
foreach my $i (@indexes) {
$password .= @{$classes[$i]}[rand @{$classes[$i]}];
}
return $password;
}
Now, I'm not saying this is ideal code. It doesn't completely suck though, and it is pretty easily extended to cover a few things I didn't bother with. About the only significant bit I couldn't add unless I were to expend a fair amount of effort would be a bit that checked the password to see if it matched a certain number of consecutive characters of the user's name or userid. (not that such a check would be difficult, just that it would require more than a simple line of code.)
But this left me faced with a new problem. How do I address the fact that my few lines of code represent something none of the other modules do? Do I try to incorporate my code into one of the existing modules and contribute a patch to the module maintainer? Do I flesh mine out into a full module and add to the number of modules out there that meet an individual's needs but don't quite cover the bases for a majority? Do I write a module that's backward compatible with the other modules but includes the solution for my own needs in the hope that I can reduce the number of modules that have multiplied out there so far?
In the end, I've opted to take the lazy way out and post a snippet here, knowing that it will like only very rarely be found by anyone that might need it, but justifying it to myself in that it is such a short snippet that anyone could have come up with it on their own if they needed it.
Does CPAN module multiplication induce apathy and denial in anyone else, or is it just me?
Re: Password Generation and Module Multiplication
by merlyn (Sage) on Nov 22, 2010 at 20:59 UTC
|
Just an aside... this seems overly complex:
[qw( . ! / \ - : ; " ' ? $ ^ & @ [ ] = + | < > % * ~ ) , qw/ ( ) /, ',
+', '#'],
why didn't you just write:
[qw( . ! / \ - : ; " ' ? $ ^ & @ [ ] = + | < > % * ~ , # ( ) )],
since qw's can nest for those parens, or even something like:
[map chr, 32..47, 58..63, 123..126]
to really get all of the "other" characters.
-- Randal L. Schwartz, Perl hacker
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
Or just use {} as delimiters, as they aren't allowed chars. However, I'd write it as:
[split //, q{.!/\-:;"'?$^&@[]=+|>?%*~.#()}]
which doesn't trigger silly warnings because of the use of ',' and '#' inside qw. Besides, qw to get individual characters looks so awkward. | [reply] [Watch: Dir/Any] [d/l] [select] |
|
Fair enough on the complexity of the "other" characters line. It is spelled out with explicit characters specifically to make it easier to add or remove given characters from the list. At the time, I think I had some warning that came up with the nested parens. Unfortunately my memory is a bit vague on that point. Those may simply have due to been a typo at the time. I will say though that with the use of "use strict; use warnings;" I do get at least the following warning:
Possible attempt to separate words with commas at test line X.
I'm sure there are more elegant ways to write the list though, including your fine use of map chr.
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
|
|
Re: Password Generation and Module Multiplication
by jwkrahn (Abbot) on Nov 22, 2010 at 22:38 UTC
|
$password .= @{$classes[$i]}[rand @{$classes[$i]}];
That should really be:
$password .= $classes[$i][rand @{$classes[$i]}];
You don't really want a list on the right hand side of the assignment.
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Password Generation and Module Multiplication
by toolic (Bishop) on Nov 22, 2010 at 21:05 UTC
|
Your code is not self-contained. Are you using List::Util::shuffle?
Do I try to incorporate my code into one of the existing modules and contribute a patch to the module maintainer?
Yes, especially if you use a similar coding style to that used by the current author and you supply tests to validate your new functionality.
Do I flesh mine out into a full module and add to the number of modules out there that meet an individual's needs but don't quite cover the bases for a majority?
This is another good choice if you feel your code is better in some way than existing modules (faster, easier to use, easier to install, etc.). You should explicitly describe in the module's POD what differentiates your module from others.
If you go this route, try to select a module name which is similar to other CPAN modules which perform a similar function. This of course requires more of a commitment because you will be responsible for supporting and maintaining the module.
Do I write a module that's backward compatible with the other modules but includes the solution for my own needs in the hope that I can reduce the number of modules that have multiplied out there so far?
Not necessarily. How do you think you will be able to reduce the number of CPAN modules?
Does CPAN module multiplication induce apathy and denial in anyone else, or is it just me?
The number of CPAN modules has thus far not affected me in that way. | [reply] [Watch: Dir/Any] [d/l] |
|
Sorry, the code was not meant to be self contained, but merely illustrative. I'll add the use statement in the original post so as to make it more clear.
| [reply] [Watch: Dir/Any] |
Re: Password Generation and Module Multiplication
by sundialsvc4 (Abbot) on Nov 22, 2010 at 19:30 UTC
|
You might have accomplished your purpose by posting this code-block here. Showing someone who will follow you, what you did and how you did it. And, soliciting public response.
If folks ask, then a new CPAN module might be underway.
But, either way, they will kibbutz kibbitz unmercifully. ;-)
(Even when you mispel yiddish ...)
| [reply] [Watch: Dir/Any] |
|
Minor nit, and off-topic. My apologies...
A kibbutz is an agrarian commune.
To kibbitz is to offer unwanted advice.
The first is Hebrew, the second Yiddish. (Well, this *is* a language forum...)
| [reply] [Watch: Dir/Any] |
Re: Password Generation and Module Multiplication
by CountZero (Bishop) on Nov 23, 2010 at 16:45 UTC
|
What all these password complexity rules do is to actually reduce the set of possible passwords by several orders of magnitude and thereby make brute force attacks many times easier.The only way to avoid users using easy to guess passwords (their user name, or date of birth, or ...) is to not allow them to choose their own password but provide them with a random password they have to use. For real security, you cannot trust the user to come up with a strong password. As far as a computer security is concerned "ADAM" is as good a password as "uhulhbjGKVOILHS885AS72JGHS65G33". Just by spelling out the complexity rules of the password,you have made it hackers soo much easier. The only good rule as far as security is concerned is "there are no rules, other than 'throw some random characters together'.
CountZero A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James
| [reply] [Watch: Dir/Any] |
|
Not to mention you can't remember strong passwords so you tend to write them down. I once had to generate a password for some military app that was so bad, it had to be some 20+ characters without any common words, nor could you use common numbers and symbols inplace of letters, so a password like, "P@$$W0rd" wouldn't work. I ended up writing it down somewhere... in my own special code I made up so as to confuse anyone who saw it (mostly inspectors who will write you up if they find passwords written on papers glued to monitors).
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
Brute force attacks against a single password, granted.
But without complexity rules, a letter-only brute force attack or rainbow table attack against a list of hashed passwords will too easily pick off the lazy users. I'd assume the complexity rules are really designed to protect against this case.
| [reply] [Watch: Dir/Any] |
|
That, basically, is the case. The number-one most often used password is: password. Close behind them are: enter, secret.
Nevertheless, it doesn’t work. Enforcing complex password-rules simply causes more passwords to be written down. When a system is broken into, it usually is not from “forcing” a password. There are too many “other” ways into a complex system.
| [reply] [Watch: Dir/Any] |
|
|