-
-

- Go time!
- by Seriyu
- posted on Jan. 7, 2012, 1:23 a.m.
-
-
Another month has passed along with another year. However as always we've got fancy art and a tech update that you should scroll down and read if you're interested in that sort've thing. We're also on Django now! This is a good thing? I don't rightly know but that's the reason jiko does the coding work here.
At any rate we have an amazing piece of art that can really only be described as gorgeous and amazing. I think it might be hand painted too? If not it certainly looks a lot like it. Excellent work to Tofu!
Image used permission of Tofu
He's also plugging his conceptart.org sketchbook so here you go! As a note some of the stuff in this is NSFW, so take note. On the other hand it also features a photo-realistic tiger wearing a suit so I recommend it based solely on this.
As for a free game plug for this month because frankly I've come to enjoy doing it, Wakfu is an amazing MMO that just recently hit Open Beta. It is F2P entirely for the duration of the beta, and will enter a free “trial” for the actual release, with P2P premium content ala runescape or something of the sort.
Happy new year everyone!
-
Another month has passed along with another year. However as always we've got fancy art and a tech update that you should scroll down and read if you're interested in that sort've thing. We're also on Django now! This is a good thing? I don't rightly know but that's the reason jiko does the coding work here.
-
-
-

- January's Technical Update: Passwords
- by cogs
- posted on Jan. 6, 2012, 11:38 p.m.
-
-
Welcome to the new year! As promised the site is officially running on Django, and I have little but praise for the framework. The most difficult part was just coercing Host Monster's servers (yes, at the moment I use Host Monster, for anyone interested) to actually find the project, but that was largely just my own inexperience in the matter. In a month or two I'll go over my observations, having hosted Django on three different underlying systems: Django development server (development), mod_wsgi on apache (in-house testing), and mod_fastcgi on apache (deployment on shared hosting), but for the time being I'm just going to give a seminar on security, specifically as it relates to login credentials and storing them. (Notice I did not say “passwords” and storing them securely… because we all know by now not to store the plaintext passwords, right?)
I would like to preface this conversation with the disclaimer that I am nowhere near the mathematician even your halfway average cryptography student is, so don't expect anything terribly in-depth, but I've done a fair amount of research on the options available for securing a site, and would just like to share my broad observations, and provide some useful links for other developers.
I'll start with the basics; there are four: Don't store plaintext passwords. Don't store plaintext passwords. Don't store plaintext passwords. Don't store plaintext passwords.
The temptation to just forego actually researching good hashing techniques and just do a direct comparison between what the user sends and the stored password can be powerful, but do not give in to that dark impulse! Even if you do take the high road and compare against a hash, it defeats the entire purpose if the actual password is in any table anywhere. You don't need it, and though harsh, if your users can't remember it, they clearly don't need it either. If they forget their password, just have them make a new one; the old one didn't stick well enough.
That said, what ARE good hashing techniques?
In the simplest terms, you want to be able to generate a hash which is both unique to the thing being hashed, and difficult to reverse engineer; ideally impossible to reverse engineer. As an example of the latter, take this:def hash (password): return 1
This is a dumb example, I know, but I guarantee you, no matter what hash you get out of that (hint: it will always be 1), you won't be able to tell what the original password was. No amount of looking over the code will let you mathematically reverse engineer the original password. However, this is not a useful hash, because it is in no way unique. Now look at this:function hash (password): hash = "" # empty string for letter in password: hash = hash + chr(ord(letter) + 1) return hash
This code might require a bit more explanation for people unfamiliar with ascii. This will take each character in the given password, and move it to the next letter of the alphabet (a->b, b->c, etc.), so “bob” as a password would be returned as “cpc” (we'll ignore that z ends up going god knows where for now). This satisfies the unique requirement, but I think you can all see how this would be simple to crack to get the original. Now, I will restate that I am not a cryptographer, but suffice it to say there are ways of satisfying both, so the hash is basically only able to go one way (you can make the hash, but not algorithmically find the password), and yield unique hashes. This is why modern hacking is so reliant upon brute force attacks, where every combination of letters is attempted and run through the hashing algorithm. With a password like “bob” it would not take long to try all the three letter combinations to find the hash, and once you get it, you will know the plaintext password, and that is exactly what we would like to avoid. The variable now is time.
I was always impressed by how quickly md5 or sha258 was able to parse through even video files to generate a unique hash, and in the computer world faster means better! Right? Well yes and no. Yes, md5 and the shas are fantastic little algorithms which can create unique hashes very quickly (some more uniquely than others), but that's not really desirable when it comes to password hashing. You want it to be as hard as possible to crack a hash, and that means take as much time as possible. Now, don't leave your users sitting around waiting for their password to validate for half an hour, but the difference of 0.1 to 0.3 seconds can mean everything in terms of security.
Frankly this page is the best description of why bcrypt should be used over most common hashing algorithms. My little tirade here is barely even noteworthy in comparison, but the more references to that page which exist on the internet, the better. The essence of crypt is that it has a “work factor.” What this does is cause the algorithm to repeat a part of the state generation code 2^workfactor times. The significance of this is that it directly corresponds to Moore's law, you know, that famous one that said that the speed of hardware doubles every two years, so in theory, if your particular work factor takes 1 second to run this year, it will only take half a second in 2014. As already stated, the main thing we are fighting in staving off brute force attacks is time, so we NEED our algorithms to keep up with this standard. With blowfish, it is as simple as adding 1 to the work load every other year; other algorithms are not as accommodating, and are, indeed, built to be as fast as possible. Now, by no means is bcrypt the ONLY good hashing algorithm out there, but it is one of the most widely used and tested ones, not to mention free, so it's a pretty safe bet.
When bcrypt generates a hash, it also generates a salt. No matter what you use, a salt is necessary. A salt in terms of cryptography is anything that is attached to the password prior to the hashing process. You could choose “ted_” as a salt, which would mean that, prior to hashing, our “bob” password would become “ted_bob”. This adds an extra layer of security to the process, by:
A) It makes the password longer and less predictable
B) It makes a rainbow table less viable
The more random the salt, the less viable a rainbow table becomes, and thus you wouldn't really want to use “ted” for all of your passwords. However, if you use an honestly random salt, you have to store it somewhere. Commonly this is done in a separate field in the table that contains the hashed passwords, but bcrypt makes this easy by storing it in the hashed string. Here's an example:>>> import bcrypt >>> bcrypt.hashpw('bob',bcrypt.gensalt(10)) '$2a$10$zqjsC1Q6kylT7R1VuR/lceuMS58Pky7tkmlrdVTTjplDgyggspjlW'
So I have just hashed the password “bob” using a work factor of 10 (bcrypt.gensalt(10)) and it has returned the displayed hash. (This is all using py-bcrypt, by the way). The $ signs separate out the different aspects of the hash. Immediately after the hash, the $2a specifies that we are using bcrypt, then comes the work function, and the rest of that mess is the salt+hash in 64bit encoding. The first 22 characters decode to the 16 byte salt, and the rest is the actual hashed value. When we try to check a password against our stored hash, it pulls out the salt, concatenates it and the password, and then performs the hash as specified.
All of these algorithms are publicly available. That is an important note to make. Unless you generate your own home-brewn algorithm, everybody else has access to the code which generated your hashes, and I shouldn't have to tell you why trying to make your own is a bad idea unless you are 100% familiar with how all of them work (and if you actually are 100% familiar with how all of them work, I have a hunch you would know better than to make one by yourself anyways). So even with all the salts in the world, you will never truly have an algorithm which cannot be brute forced. Our job as the holders of these passwords is not to make it impossible to crack them; that is not realistic. But we want to make it take more resources than most people can have at their disposal to accomplish the task. We want to make it as obnoxious as possible to get the information they want, and as uninteresting as we can manage. So if we can make our hashing algorithm take a second to complete one hash, then the number of people willing to sit down and take the time to brute force our passwords is diminished significantly. If we can furthermore suggest that we have nothing of interest, the number is cut down yet more. Cracking is a fun exercise, I'll admit that, but when you're looking at a couple weeks of just waiting on results it becomes much less of a puzzle to solve, and much more a monotony. We don't have to try to think of the fastest and most streamlined algorithm to produce the most uncrackable password (as noble of an endeavor as that is), we just have to convince anyone interested that it's not worth the effort. All these methods basically give us the time to contact our users and get them to change their passwords in case of a breach.
Anyways, I hope that was at least somewhat useful and accurate. The reason for the topic is just because I was reimplementing my login tables in python so I had to track down a crypt implementation for python since django doesn't use it by default (for shame!). Anyhow! For the present I'm just reorganizing code and recreating the Spiral Knights Calculator in python as an exercise in ajax. To the future, I should be able to get the forums up and functional here soon! If not next month then hopefully the month after!
And as always Ser has found a bit of awesome to show off! For a landscape study this picture is stunning. Heck, no matter how you look at it it's gorgeous. Just… look at it. Stop reading. Look!
-cogs
-
Welcome to the new year! As promised the site is officially running on Django, and I have little but praise for the framework. The most difficult part was just coercing Host Monster's servers (yes, at the moment I use Host Monster, for anyone interested) to actually find the project, but that was largely just my own inexperience in the matter. In a month or two I'll go over my observations, having hosted Django on three different underlying systems: Django development server (development), mod_wsgi on apache (in-house testing), and mod_fastcgi on apache (deployment on shared hosting), but for the time being I'm just going to give a seminar on security, specifically as it relates to login credentials and storing them. (Notice I did not say “passwords” and storing them securely… because we all know by now not to store the plaintext passwords, right?)
-
Follow @springlessclock