“Those are my principles. If you don’t like them I have others.” Groucho Marx
“Thou shalt not entertain any firm beliefs.” Good or bad, that’s not important. Intuitive, or based on the best science, it doesn’t matter either. What seems to matter now is that you should never be certain of anything.
This age demands that you remain ignorant, despite the unprecedented amount of knowledge this age amassed. No matter how much you know (or feel) is right, you should not base your confidence on your certainty. “You must never be certain”, is what is asked of you. And it prepares the ground for “every opinion is valid.” Coupled with “anyone is entitled to their opinion on anything”, this heralds the end of civilization.
Hashing provides one-way encryption. This means there is absolutely no way of recovering the original string that was hashed, from the hash string. Hashing has a significant ammount of mathematical theory behind it, most of which you needn’t know. However, I encourage you to have a read of the relevant Wikipedia articles.
Hashes are used for two main purposes:
- to uniquely identify some information: this is achieved by hashing that information into a string that is unique within the key-space of the hashing algorithm. This is how you can quickly compare two files, for instance – by hashing their contents, then comparing the hashes. If they match, the files are identical. With one caveat: collision risk, meaning that a certain (usually very small) percent of non-identical information will yield an identical hash. This is, apparently, mathematical inevitability, it is algorithm dependent, and can be used in attacks attempting to break the algorithm. With a strong enough hash algorithm, this should not be a concern for most problems.
- to obscure information: this is why we use them for password storage, where uniqueness is not the problem.
How to store passwords (of your website’s users), you wonder? There has never been a simpler question in website security, with such a straight forward answer:
Never-ever store passwords
Store hashes of your users’ passwords, never the passwords themselves. I don’t care if you plan on storing passwords in a file or in a database table, whether in plain-text (…yes, there have been cases, some notorious) or two-way encrypted. Forget all that. Just use good password hashes, always. Hashing is one-way encryption, meaning the result (hashed string) cannot ever be used to directly retrieve the original text, as opposed to two-way encryption, where the string can be decrypted back to the original, using the encryption key.
Your mighty user authentication mechanism, which you’ve spent countless hours developing and testing, and is now, theoretically, full-proof, will be rendered useless if you or your users choose to use weak passwords. Hence the need to enforce strong passwords.
Without going into to much explaining, what makes a weak password?
- password is short: the shorter the string, the easier to guess it, and the inherent drop in potential complexity only helps guessing: boob2 is a weak password.
- password contains common words: “dog”, “bread”, “bacon”, “concupiscence”, you name it. If the word can be found in a dictionary, it is a common word. Avoid l33t speak, too.
- password contains special words: the very user name, the name of the website/system where the password is being used
- one (upper or lower) case letters only: this automatically halves the potential complexity of the password string.
- no digits: there are no digits (0-9) in the password string.
- no special characters: there are no special characters (e.g., *^&£:]’) in the password string.
There are two main ways to implement security in a system. They should always be used together, for reasons that will become obvious.
Security through obscurity
This means keeping critical parts of the system you’re designing a secret. Keeping your code closed source, not disclosing the structure of your system, etc.. The extreme example would be keeping the domain name of your website a secret…
Dr. Bimal Chhajer in his book “Heart Attack” writes about a diabetic male patient, 55 years old, who noticed some breathlessness on the way to his office. After consulting his physician and routinely passing the ECG exam, it showed that he was just experiencing a silent heart attack. In such moments every second counts, so he was rushed in the emergency room immediately.
With the USA being on the third place in the world in the top countries of patients with diabetes, there’s no doubt that a specific attitude must be approached when we speak about the silent myocardial infarctions in these patients. The chances of experiencing a heart attack in a diabetic sufferer increases with the age, because of the capillary damage, and The chances of it developping without any symptoms increases as the nerves become damaged, too.
Where do I store my database credentials?
There comes a point, in security matters, when developers run into the age-old question: “Who was first? The chicken or the egg? Or the hen? Perhaps the fowl?”
You (your scripts) need an user name and password to access the database server. Where to securely store these? Yes, in a database table! What an elegant, secure solution! Oh, wait… You need an user name and password to access the database server in order to retrieve the user name and password required to access the database server.
The (generically titled) “system” directory of your website or web application should be the one containing all the scripts required for system administration, completely separated by all other files. To achieve maximum security in this regard, here are some important guideliness:
System directory name
- do not name the “system” directory “system”, or “admin”, or “root”, etc.. Instead, choose an unusual and cryptic name, and use a global variable in your code to hold this name. This way, the default “system” directory can me renamed and moved deeper into the file system, provided the global variable is hard-coded with the same value (eventually including the relative path). If you’re building a system that get’s deployed to others, teach the (future) admin to do this before going live.
- URL rewriting to access the “system” directory should only be used on top of the action described above.
- “system” directory name should not be made apparent to any visitor or registered user, except system administrators, who would get a link taking them to the admin interface located in this directory
- scripts running in the “system” directory (say, example.com/system_dir_name/some_settings.php) should display no direct outbound links (to other websites)! Reason being, the HTTP Referer header will contain the URL, compromising the secrecy of the “system” directory name.
You may be developing a simple, straight forward personal website, containing information that’s both public, and easy to back-up, and so implementing proper security measures doesn’t present much interest. However, no matter how simple or low-value your system is, it is definitely not your intention to have it defaced by hackers. Failing to secure your website guarantees that, sooner or late, it will be defaced, if only for the lulz. Happened to me? Oh, yes.
Stuff you have no excuses for, no matter what you may come up with. I know, you’re so above and beyond this, but simple things are often the easiest to overlook, and when they go wrong they tend to do the greatest damage. Before pondering on which encryption cipher to use, make sure you’ve got these covered.
- sticking your FTP/website admin credentials on a post-it on your monitor
- keeping any admin credentials in a plain-text file on your webserver, which, when accessed, will not undergo any server-side processing (such as happens to a PHP script), but will be simply displayed in browsers
- letting your sensitive directories (containing sensitive administrative data) be accessed from the web, including as indexes
- diluting security of your admin credentials by holding them in potentially insecure online storage, such as your own email inbox, in plain-text
- using poor admin credentials, such as an easily guessable admin user name (“admin”, “administrator”, “webmaster”, “root”, etc.) and a weak password (i.e. short and lower case letters only)