Information Security Programming Tips & Insights

Just Hashing is Far from Enough for Storing Passwords – How to Position against Dictionary and Rainbow Table Attacks

login passwordIt goes without saying that sensitive information such as passwords or pass phrases should never be stored in plain text in the database in the first place. The common practice is to hash the user password and store the resulted hash string. When the user tries to log in and supplies his password, it is used to generate a hash string to be compared to the one stored in database. If they are identical, the password is matched and the user authenticated because the chance of 2 distinct strings having the same hash string is so low that it’s deemed mathematically impossible.

This approach may be secure in the 70s of the last century, but barely any more. Thanks to unprecedentedly cheap computing power now, rainbow tables, the mapping function from hash strings to any possible combinations of keyboard characters (alphanumeric, punctuations, etc.) have rendered this password storage / validation method insecure. With a mapping table of trillions of hash to cleartext pairs, it takes only 160 seconds to crack the password “Fgpyyih804423” which most of us would generally agree is fairly safe.

What can we do?

Provide a random salt when you are hashing the secret text. For instance with the PHP’s SHA1 hashing function:

$my_hash = sha1('whatever salt you put here would do,,,???'.$secret);

As you can see, the salt string can be whatever you like, in a random manner, prefixed and / or suffixed to the secret text before it is hashed into a hash string which will be stored. This way, because the cracker has no idea what the salt is, there’s no way he can create the right rainbow table to perform the crack. Even if he does, he would have to specifically build a rainbow table to crack your database which can be time-consuming. Subsequently, to make this even more difficult for the cracker, you can use different salts for each of the password entries in the database:

$salt = generate_random_salt(); // your in-house function that generates a random salt, perhaps by uniqid('some random string', true)
$my_hash = sha1($salt.$secret); // the $salt must then be stored in your database on a per entry base
// this function is the same as hash('sha1', $salt.$secret), but a better algorithm would be hash('whirlpool', $salt.$secret)

When the salt string is a per application constant, you can store it rather obscurely somewhere in your application code. However when you use random salt strings, you will have to store it correspondingly with the hash string $my_hash in the database, or otherwise you won’t be able to generate the correct hash string of the password user provides for authentication against the one stored in database.

It doesn’t even matter if the cracker gets the database and knows all the random salts, because he’d have to create and run through a huge rainbow table specific to each of the random salts to crack just one password. It’s so squarely and prohibitively time-consuming that he’d definitely give up.

A better yet approach to defend against rainbow or dictionary attacks is to be creative in generating the hash string – such as taking the username string into the generation and implementing multiple layers of hashing, in a playfully diversifying manner.

At last, it is recommended that you generate the initial hash string (the one to be stored in database) by running 1000 iterations of hashing instead of just 1. The extra computing burden on your server is negligible while it will increase the time needed to crack a single password by 1000 times at the cracker’s end. The point is to make the hashing process as slow as possible rather than the other way around. As the cracking usually makes password guesses and trial logins at a much higher paced speed, the slowness will have a much more detrimental effect on the cracker than on your website.

Information Security PHP Tips & Tutorials Regular Expression Tips & Tutorials

PHP: Check or Validate URL and Email Addresses – an Easier Way than Regular Expressions, the filter_var() Function

To check if a URL or an email address is valid, the common solution is regular expressions. For instance, to validate an email address in PHP, I would use:

if (preg_match('|^[A-Z0-9._%+-][email protected][A-Z0-9.-]+\.[A-Z]{2,4}$|i', $email)) {
	// $email is valid

A simpler and more forgiving one would be:

|^\[email protected]\S+\.\S+$|

Which is usually quite enough for signup forms in preventing stupid typo errors. You get to validate the email by a validation link sent to the address anyway, as a final call whether the address is valid or not. For those who are obsessively curious, this may serve you well.

For URL, you can use this one:


Or you can use one that is insanely detailed in addressing what a valid URL should be.

The filter_var() function of PHP5

What we are talking about here really is the filter_var() function of PHP5 that simplifies the URL and email validation by a large degree. To validate an email:

if (filter_var($email, FILTER_VALIDATE_EMAIL) !== false) {
	// $email contains a valid email

To validate a URL:

if (filter_var($url, FILTER_VALIDATE_URL) !== false) {
	// $url contains a valid URL

While filter_var() is meant to return the filtered results of the input according to the filter type specified, such as FILTER_VALIDATE_EMAIL or FILTER_VALIDATE_URL, you can generally use it to see if a valid email or a valid URL can be extracted from something. Better yet, filter and get the results first, use the result if it is good or abandon it when it is false:

$filtered_email = filter_var($email, FILTER_VALIDATE_EMAIL);
if ($filtered_email !== false) {
	// $filtered_email is the valid email got out of $email
} else {
	// nothing valid can be found in $email

Same applies to FILTER_VALIDATE_URL. Here’s a full list of filter types of filter_var() you can take advantage of.

Information Security PHP Tips & Tutorials

PHP: Allow Specific HTML Tags in Text Input Controls of HTML Forms, <textarea>, <input type=”text” />

Textarea and text input are common html form controls that accept text input. They can be a security challenge as they allow the user to enter anything they want. If you just go about using whatever data the user has entered, your application is anything but secure. Some sort of filtering / white-listing must be in place to protect the integrity of the application and you need to permit or allow only a few special HTML tags in the textarea control of the HTML forms.

The simplest way is to denounce any attempts to add HTML tags in the text box control is the PHP function strip_tags():

$all_tags_filtered = strip_tags($_POST['message']);

Wherein $_POST['message'] is the text just submitted by a user, containing all sorts of HTML tags. Thanks to the function strip_tags(), all the tags are now gone in $all_tags_filtered. The data in $all_tags_filtered is safe to use as it’s plain text.

However, there are times when you want to keep a few simple tags for the user’s convenience, such as <p>, <strong> and <em>. To do this, just feed a second parameter to the function strip_tags():

$some_tags_filtered = strip_tags($_POST['message'], '<p><strong><em>');

So <p> elements, <strong> elements and <em> elements are kept intact while all the other tags are gotten rid of in $some_tags_filtered.

One important thing to note is that strip_tags() does not check the attributes of the allowed HTML tags. The attributes of the allowed HTML elements such as style="" and onmouseover="" are kept as they are in the filtered results which may lead to other security problems. You have to use regular expressions to erase them out and block attached malicious attempts.

Information Security SQL / MySQL Tips and Tutorials

A few database security tips – things to do to effectively protect MySQL databases

I’d like to share with you some tips about hardening the database part of your application. Here are a few things you can do in protecting the databases from being compromised in security:

  1. Create separate users with ONLY necessary privileges (as few as possible) to connect to the database for common daily tasks. Never use the database owner / creator or even MySQL root user in your PHP scripts to perform routine tasks.
  2. Protect against SQL injection attacks by escaping ALL incoming input after ensuring data types with a variety of PHP variable type and character type validation functions.
  3. The sprintf() function is both useful and secure in constructing SQL queries because of the built-in type checking. Better yet, use PDO.
  4. Turn off error messages MySQL or PHP outputs when things go wrong so crackers know nothing about the technical details of your build such as database schema. As a matter of fact, a good rule of thumb in web application security is that the less people know about your application’s internal structure, the better.
  5. For advanced SQL developers, extra abstraction layer in SQL in the form of stored procedures can benefit security because you implement yet another depth of defense and hide the schema of the database from the outside world.
  6. For mission critical applications, it goes without saying that custom logging of database accesses can help a lot in identifying security risks.
  7. If the database contains very sensitive data such as credit card information, you are strongly recommended to encrypt these tables or fields. Just use PHP cryptography extensions such as Mcrypt to encrypt any data that are to be stored and decrypt them when they are being retrieved.
Information Security PHP Tips & Tutorials

One Simple Way to Encrypt, Obfuscate, Hide or Protect Your PHP Code

This way is so simple that anyone who’s a beginner in PHP can use it immediately to obfuscate and hide the original PHP code. Generally, it’d make it much harder for someone to find a specific phrase in your code as it’s encrypted, though in a rather simple way using 4 PHP functions: gzinflate(), gzdeflate(), base64_encode() and base64_decode().

For example, you can make it eventually impossible for someone who know nothing about PHP or programming to modify your code and some of your native strings. It comes quite handy in encoding, obfuscating and protecting your credits lines in the footer of your scripts of web software.

Say here is the line of code you want to hide from being modified:

echo "You can't find me!"; // it’s “echo” instead of “echo”, same below. Have to post them this way because of a WP bug.

You can get the obfuscated and encrypted version of this line of code by:

echo base64_encode(gzdeflate('echo "You can\'t find me!";'));

Which would output:


This is the code you should use in your script. As it’s all encrypted and obfuscated, the original string and code are totally hidden, protecting them from being changed.

To run the hidden code, replace the original line of code with this one:


It’s simply the reverse of the encoding plus an eval() function of PHP. And because all the original code and strings are totally encrypted in obfuscation, it’d be harder for non-programmers to modify your script but not professionals. For absolute protection of your code, use Zend Guard.

Information Security PHP Tips & Tutorials

PHP: open_basedir in php.ini to Restrict and Limit PHP File Accesses to a Certain Directory

The open_basedir directive in php.ini limits PHP file accesses (such as file opening, writing and deleting) within a designated directory such as /home/www/public_html so that it doesn’t endanger the rest of the system in any way. With proper Apache permissions and PHP installed as an Apache module, PHP inherits whatever privileges Apache has. As Apache is usually endowed with very limited permission in the form of a ‘nobody’ or ‘www-data’ group, there’s actually no need for open_basedir.

So it’s actually turned off by default. Controversies are raised about whether to use it or not. While it’s good to have extra confinement of what your public PHP scripts can access and do, it’d also make your applications reliable on it for file system security.

To modify the value of this directive and restrict php directory access, just find php.ini and locate the line:

;open_basedir = 

And change it to minimum directory access your PHP applications need such as the web documents root:

open_basedir = '/home/www/public_html'
Anti Spam Tips & Tricks Content / SEO Tips & Tutorials Google Hacks, Cheats & Tips Information Security

How to know if your site has been penalized by Google for malicious software or suspicious content?

Back when WordPress was pretty young there’s some loopholes that enable hackers to inject unauthorized and dangerous HTML code into your website pages, thus promoting the distribution of malware that damages the end users computer. I was once there and got penalized by Google for one of my sites. However, they are gentle enough to detect that this might not be my fault but still decided to bring down the overall ranking of all the pages on that site for a while to protect Internet users and notify me.

If you have spotted anything suspicious or sense that your overall site ranking is down, you may want to check it out for sure if your site has been infected with malware or anything else that’s a threat to your site and the visitors.

Just go here:

And Google will present you a detailed report of what they have found on your site for the last 90 days.

Anti Spam Tips & Tricks Information Security Web Applications & Online Software

phpBB Spam Control – phpBB Anti-Spam Options for Fresh Forum Installations

phpBB is pretty much the best php forum software out there that is free, and comes the first choice of many webmasters. However, after a few weeks of first installation, many complain that spam bots start to overwhelm their forums, flooding with automated spam registrations and spam posts.

Unfortunately, that is generally because:

  1. phpBB disables account activation by default so that any registered account would be instantly able to write and submit posts.
  2. The default image captcha at registration is much too easy for anti-captcha programs to break.

So, taking phpBB 3.0.4 for an example, to prevent the majority of simple phpBB forum spam bots, with every new phpBB installation, you will:

  1. Enable registration activation: Administration Control Panel => General => (Board Configuration) User registration settings => (General settings) Account activation => Now select ‘By User‘ from ‘None‘ => Submit.Thereby all new registered accounts will be required to validate the email address which no automated spam bots would do with fabricated ones, at least for not-so-valuable new forums.
  2. Use harder captcha images: Administration Control Panel => General => (Board Configuration) Visual confirmation settings => (General options) => GD CAPTCHA foreground noise => Select ‘Yes‘ instead of ‘No‘ => Submit.This would make the captcha a lot harder to break but also less user friendly / accessible because the texts are also much harder for human recognizing. To ease the pain, you may want to set the numeric values just below the option for background noises of x-axis and y-axis higher or zero. I use 200.

After all these efforts you should be receiving much less spam now. If they still laugh at your defense and keep on coming, you should consider using more advanced image captcha such as

For an idea of what captcha works best

Below is a list of famous Chinese websites image captchas that have allegedly been broken by automated text recognition programs with an accuracy percentage and price for each of them. From them you can get an idea of what captcha works the best and what can be easily worked around.

Origin Samples Accuracy Price Comments
9you captcha broken by spam bots 100% 500
Very Easy
tiancity captcha broken by spam bots 100% 500
Very Easy
cncard captcha broken by spam bots 100% 500
Very Easy
the9 captcha broken by spam bots 100% 500
Very Easy
the9 captcha broken by spam bots 99% 1000
kingsoft captcha broken by spam bots 98% 1000
taobao captcha broken by spam bots 95% 1000
dvbbs captcha broken by spam bots 95% 1000
126 captcha broken by spam bots 95% 1000
163 captcha broken by spam bots 95% 1500
shanda captcha broken by spam bots 90% 1500
qq captcha broken by spam bots 90% 1500
xiaonei captcha broken by spam bots 85% 1000
sdo captcha broken by spam bots 85% 1500
ourgame captcha broken by spam bots 80% 1500
chinaren captcha broken by spam bots 85% 2000
monter captcha broken by spam bots 80% 2000
baidu captcha broken by spam bots 80% $3000 Difficult
qq captcha broken by spam bots 75% $3000 Difficult
ebay captcha broken by spam bots 60% $4000 Difficult
myspace captcha broken by spam bots 30%
google captcha broken by spam bots 30%
hotmail captcha broken by spam bots 30%
yahoo captcha broken by spam bots 45% $8000
Content / SEO Tips & Tutorials Information Security

Robots.txt Disallow All and Block Search Engine Spiders

You can literally block any visitor including search engines and secure the data or information you have on your website by the help of .htaccess Deny From All. A similar solution is to have a robots.txt, majorly for search engines.

To disallow all search engine visits and stop the any spider or crawler, create a robots.txt and put the follow text in it:

User-agent: * Disallow: /

That’s a rather strong statement of close-up, as after you have placed the robots.txt file in the document root of your domain, almost all search engine spiders would stop accessing and indexing your entire site, preventing the precious information that you want to keep private from leaking outside.

Usually, you just want a sub folder / directory under the domain to be excluded from the search engine crawling scope, then below is what you need:

User-agent: * Disallow: /data/

Similarly, put the robots.txt at the root directory of the domain, and all play-by-the-rules search engines would never break your privacy by accessing any more.

Information Security PHP Tips & Tutorials SQL / MySQL Tips and Tutorials

PHP: Escape String Literals for SQL, mysqli::real_escape_string and PDO to Prevent SQL Injection Attacks

To successfully run a query with text data containing single quotes ‘ as well as other SQL reserved punctuations, AND to prevent SQL injections, you will always want to escape the text values before using them in a SQL query.

In PHP 4.0, we are stuck with mysql_real_escape_string. With PHP 5.0, mysqli:prepare and mysqli::real_escape_string are better choices:

$city_name = "Xi'an"; // one of the top travel destinations of China
$mysqli -> query("SELECT * FROM `cities` WHERE `name` = '" . $mysqli -> real_escape_string($city_name) . "'");

If the string value $city_name is not escaped, the SQL query would look like "SELECT * FROM `cities` WHERE `name` = 'Xi'an'" which is grammatically erroneous and will be rejected by the SQL engine because of the unpaired single quotes at the end. Without escaping of the value, malicious users can make up their own WHERE clauses to append to yours to do much more to your database than you want.

Other than these, some would prefer the PDO class to prepare a SQL query, inject literal string values and then execute it. It takes a real OOP approach to the problem and is much more intuitive in accomplishing the job, yet slightly inferior in efficiency to the mysqli real_escape_string function.