.ToString(theory);

My travels in the .Net underworld

  Home  |   Contact  |   Syndication    |   Login
  19 Posts | 0 Stories | 0 Trackbacks

News

Archives

Post Categories

So, I haven’t been able to write in a while to do an absurdly busy work schedule, but in the mean time, I’ve been able to accrue a lot of subjects to do my return blog post on.  Out of the 10 or so I have pending, the most important one that I wanted to bring up, isn’t even .Net specific, but is an authentication issue – passwords. 

Now, being the diligent IT person you are, I am sure that your passwords are all secure.  However, in my work lately, I have come to work with a client who’s system requires the artifacts of a secure password, but in its implementation of this scheme, makes the password insecure.  Kinda the wrong idea if you ask me.  In this article, I am going to just briefly cover this scenario, and give my ideas on password security implementations.  I would love to hear your feedback.

The Good

In its most simplest sense, I would define a basic secure password as such:

  • Doesn’t contain any of the basic dictionary words such as password, 12345, etc.
  • Contains letters
  • Contains numbers
  • Contains symbols
  • Contains letters of both cases
  • Has a length of 10 or greater

Now obviously, a password that is 10 characters, and matches the above conditions is secure, but a few more characters for length and a completely random body instead of any word would be more secure.  As it stands, a 10 character password would take roughly 96 years to crack on a desktop PC (source: https://howsecureismypassword.net/).  I generally have 14-20 character passwords with all cases above, and are random not words.  I am still trying to figure out why I forget peoples names and faces, but can remember these monstrosities.

To clarify the ‘basic dictionary words’ statement above, I say this with the idea that if you say that your password CAN’T contain any WORDS in it, then you end up with a complex jumble of characters.  Now, while I can for some reason remember almost every password for every client and don’t write any of them down, even the crazy ones, I’m not like everyone else.  Most end users will end up writing down their passwords if they get to unworldly, which kills any security their could be around it.  I don’t know how many security audits I’ve seen fail because some user wrote down a username, password, and server address on a post it, and then threw it away later, WHILE THE CREDENTIALS STILL WORKED!!!

The Bad

Now coming to the main point, is when password security/specifications go too far.  As mentioned before, with a client system I have come across.  Their systems password requirements are strict to say the least:

  • Passwords can only be exactly 8 characters long
  • They must have at least 1 letter, 1 number, and one special character
  • All letters must be lower case
  • No two consecutive characters can be the same (ex: 00, bb, !!)
  • Passwords can only end with a letter or number
  • Only – ^ % | =  are allowed as a special character
  • You can’t have a common dictionary word

So, what has effectively been done here, is a complete restriction on the password, basically to the point of giving it a schema – a defined pattern or scheme.  In other words, instead of having to brute force the password if I were an attacker, I could SIGNIFICANTLY decrease the number of passwords that I would have to try.  Having spent just 2 minutes to write an application and count the passwords in a matter of 3 minutes, not including their dictionary rule which would eliminate several percent of these possibilities, the total number of passwords in their schema is 3,740,347,317,070.  While that may seem like a big number, to a computer, that is NOTHING!

Below, I list changes that they could make to their schema/restrictions in order of benefit to the number of available passwords:

Original Schema
Possibilities: 3,740,347,317,070
Factor of Original Schema: 1

Allow Consecutive Characters
Possibilities: 6,156,135,096,336
Factor of Original Schema: 1.6458725820035363

Allow – ^ % | = in all places
Possibilities: 7,984,925,229,121
Factor of Original Schema: 2.134808495638846

Allow ALL Symbols (32 visible on keyboard) in middle
Possibilities: 128,132,257,480,704
Factor of Original Schema: 34.256780619259807

Allow uppercases in all places
Possibilities: 347,722,021,057,636
Factor of Original Schema: 92.965169162425255

Allow ALL Symbols in all places
Possibilities: 457,163,239,653,376
Factor of Original Schema: 122.22480986377883

Allow uppercases in all places, no symbol restriction
Possibilities: 6,095,689,385,410,820
Factor of Original Schema: 1629.7121279597834

All of these are based without the dictionary check, and are all of length 8.  Looking at this, it is clear to see how being too strict in an attempt for a secure password, can actually be worse!  The thing is, I’ve seen this same situation on multiple websites and clients.  The best thing you can do for the password, is restrict the basic dictionary words, enforce a MINIMUM length, and let the user provide whatever they want.  Then no one can provide a schema that would effectively reduce the number of possibilities to a reasonable number, hopefully.

The Ugly

Last statement I want to make, is more of a small rant than anything else I suppose.  In my mobile carriers push to make passwords more secure (but a LARGER pain to their users), they instead introduced an interesting bug.  My password had a ‘v’ in it.  Come to find out, their system would strip out v’s in passwords when logging in, but not when creating (or vice-versa, I can’t remember which – it creates the same predicament though)! 

Their reasoning/cause for this – they don’t want users to be paste in their password via CTRL+V………………  WHAT?!  I ended up having to reset my password 3 times before I finally opened a ticket after changing it, logging out, and trying to log back in immediately with the same password.  Not cool un-named carrier..  Not cool at all.  Last I checked, they still haven’t fixed the issue.

The Code

So, for this post, I wrote a quick LinqPad program to do all the calculations.  I have it below if you’d want to check for errors.  There are definitely faster/better ways of writing it, but for a quick smashout just to get the stats, it works well for me, only takes 3 minutes to compute the password possibilities.

void Main()
{
	//execute CountPossibilities() to get the count
	AddStatistic("Their schema", CompaniesSchemaSolutions);

	//allow consecutive characters
	AddStatistic("Allow Consecutive Characters", 36*Math.Pow(41, 6)*36);

	//32 symbols + 26 lowercase + 10 numbers
	AddStatistic("Allow ALL Symbols (32 visible on keyboard) in middle", 36*Math.Pow(68, 6)*36);
	
	AddStatistic("Allow – ^ % | = in all places", Math.Pow(41, 8));

	AddStatistic("Allow ALL Symbols in all places", Math.Pow(68, 8));

	//same symbol criteria as company enforces, none at beg/end, only 5
	AddStatistic("Allow uppercases in all places", 62*Math.Pow(67, 6)*62);
	
	//26 low, 26 high, 10 num, 32 symbols
	AddStatistic("Allow uppercases in all places, no symbol restriction", Math.Pow(94, 8));
	
	Statistics.OrderBy(x=> x.FactorOfOriginalSchema).Dump();
}
public long CompaniesSchemaSolutions = 3740347317070;

public void AddStatistic(string description, double calculation)
{
	Statistics.Add(new UserQuery.Statistic() {
		Name = description,
		AllowableValues = calculation.ToString("N0"),
		FactorOfOriginalSchema = (calculation/CompaniesSchemaSolutions)
	});
}


public List<Statistic> Statistics = new List<Statistic>();
public class Statistic
{
	public string Name { get; set; }
	public string AllowableValues { get; set; }
	public double FactorOfOriginalSchema { get; set; }
}

public long CountPossibilities()
{
	long passwords = 0;
	int char1 = 0;
	for (int char2 = 0; char2 < 41; char2++)
	{
		if (char2 == char1)
			continue;
		Enumerable.Range(0, 41).AsParallel().ForAll(char3=>{
			long minicount = 0;
			if (char3 == char2)
				return;
			for (int char4 = 0; char4 < 41; char4++)
			{
				if (char4 == char3)
					continue;
				for (int char5 = 0; char5 < 41; char5++)
				{
					if (char5 == char4)
						continue;
					for (int char6 = 0; char6 < 41; char6++)
					{
						if (char6 == char5)
							continue;
						for (int char7 = 0; char7 < 41; char7++)
						{
							if (char7 == char6)
								continue;
							for (int char8 = 0; char8 < 36; char8++)
							{
								if (char8 == char7)
									continue;
								minicount++;
							}
						}
					}
				}
			}
	
			lock (syncLock)
			{
				passwords += minicount;
			}
		});
	}
	return passwords*36;
}

private static readonly object syncLock = new object();

Conclusion

So, in the end, I have to believe that they have some reason for such draconian password rules that hinder their security.  I suppose I can see that maybe, just maybe, they have some of the requirements due to unified passwords for multiple legacy systems.  While I can understand the want to go unified, there is a major trade off.  I would much rather see a randomly generated password for each user per application stored in the database associated with their user record, and encrypted with their password.  then, each time they wanted to cross systems, enter in their main password again.  I am not saying store their main password in an encrypted state either.  Main password should be hashed with a salt, which is why they would have to re-enter it, and it would be lost in the ether once again after decryption for the app password.  This may not be the greatest solution, but I find it much better than restricting your password choices to the point of a blueprint on how to attack them.

Thoughts?

posted on Saturday, June 1, 2013 4:04 AM

Feedback

comments powered by Disqus