Security Levels from JavaScript and PHP Input Filtering
Also see:
- Security Levels and PHP
- Security Levels from Captchas and PHP Input Filtering
- Exiting from a PHP Form Validator
Security is a funny thing. There are dire predictions and massive paranoia about data from users, preventing MySQL injection attacks, stopping hackers in their tracks so they don't crash your site, wreck your databases, corrupt your data, hijack your site—and the list goes on. We've had a lot of sites for 8 years, and they have plenty of forms, and we had one incident where some creeps were using one of our sites for sending out spam at such a rate the host closed it and we ended up with a new email address and new safer CGI form handler, after which our site reopened. And once some creeps usurped a form of ours to send us nasty emails.
Other than that, we get a bit of spam just like everybody else. We had no special user input filtering during that time—most smaller sites don't. There's not that much to gain from messing with us since we use only the most secure servers with the highest level of security and 128-bit encryption for when we get orders for products at one of our sites, and we have security certificates, a great credit rating, a good rep, and the whole 9 yards. And orders are all dealing with small amounts of money. Like thousands of other ecommerce companies doing business online, we've never had a single security issue regarding money, credit, online safety, credit cards, identities, etc.
So the 2 incidents that happened were merely nuisances—easily fixable. We use an email address scrambler to prevent form spam and spam filters on our email. This has killed the form spam. The spam filters and the use of a few disposable email addresses that allow greylisting has greatly reduced the spam.
So we don't feel like a great emergency exists for most smaller sites regarding input filtering, and it's obvious other sites feel the same way, since not that many bother with filtering form data from users.
That said, however, the threat of hacker attacks is very real, and it will always be a clear and present danger to webmasters, site owners, hosts, ecommerce, etc. If you want to be 100% safe in this world, use a guillotine. From that moment on, you will be 100% safe from anything doing you any further harm. But in the real world, one has to make choices. How much effort should go into security to prevent what may never occur? Big companies, banks, Facebook, MySpace and the like all need great security. The Defense Department and the electrical grid needs even better protection. But you—what do YOU need? Each of us has to decide that for himself, herself, or—in the case of companies—itself.
We'd like to help by laying a few security tactics on you which we hope you will find useful. First off, do JavaScript input validators do any good? (Examples: regular expression general input validator, regular expression username validator, regular expression password validator, regular expression email validator, and regular expression url validator.) Yes and no (PHP validators are much better). If a noobie hacker is just goofing around in one of your forms, it will stop the bad characters because an onSubmit sends the data to a validator prior to submission. But it only works if JavaScript is turned on in a hacker's browser. So a smart hacker leaves it off. Oops! There goes the input filtering! Oh well, who ever said life was fair? So hackers are getting easy pickings at your site due to its reliance on JavaScript-based security measures, easy to overcome. Is that your problem, Bunky? Here, then, are suggestions and these countermeasures are not to be seen as infallible, but as progressively useful. We go from simplest (least secure, but still helpful) to most complex (most secure):
- To send users with JavaScript disabled to a special page, create a page called no-js.htm. Put this in the HEAD section or the BODY section it that works better for you: <NOSCRIPT><meta http-equiv="refresh" content="0;URL=no-js.htm"></NOSCRIPT> Some webmasters swear it works well for them, since the jerks are sent away to a page without a form, and you can have a message about turning on JavaScript in order to use that form page. Then give them an email address where, if they're legit, they can contact you about giving you the info the form was soliciting. Or they can just turn on their JavaScript! Our experience, however, is that although this seems reliable in IE6 and sometimes IE7, it won't work for many IE8 users. This seems to be because, depending on one's security settings, IE8 warns users about scripts and ActiveX controls during page load and before JavaScript is enabled. If the user says to allow scripts and ActiveX, JavaScript is enabled. However, since JavaScript is NOT enabled at first, the noscript tag kicks in AND SENDS THE USER AWAY WHETHER OR NOT HE HAS JAVASCRIPT ENABLED! So this method relies on the hacker having very low security settings or whatever else can preclude that annoying warning. Besides, Google can penalize redirects. It is such an obvious and THEORETICALLY good solution, and yet obviously the jokers at Microsoft in charge of the ActiveX warning and the jokers in charge of the noscript tag compatibility issues have never talked to each other!
- Use scramblers on your emails to prevent most/all spam.
- Use document.write("....form code....") to create your forms, thereby putting another barrier in the road for the hackers. (It also works to put these forms in DIVs and use document.write inline CSS styling to position them.) Neither the hackers nor any automatic program will even see any forms if they rely on the JavaScript disabled method. Forms created this way work fine—we've tried it. In fact they work BETTER on PHP pages than forms that were NOT dynamically generated with JavaScript. We've tried that too.
- They might leave JavaScript on until they see the form, then turn it off. So let them see the form but not the submit button—there is none yet. Then let them hit a road block when the onChange event you put in the input boxes runs a function—if JavaScript is on—that actually creates the submit button with innerHTML, but when JavaScript is off, they won't see a submit button since there will not be one.
- Have CSS styles in the HEAD section that sets the display property of the whole form to none. But then in JavaScript, use its ID with the getElementById('its_id') method to change its CSS display property to block.
- Have CSS styles in the HEAD section that sets the visibility property of the whole form to hidden. But then in JavaScript, use its ID with the getElementById('its_id') method to change its CSS visibility property to visible.
- Use the PHP Filter functions after POSTing the form data to a PHP page (e.g., in the form: <form action="welcome.php" method="post"><input type="text" name="fname"> and in the PHP page: $first = $_POST["fname"];. Better yet, use the functions in the following except modify them for PHP use, since our URL and email validators are—we claim—better than the PHP functions in the filters: regular expression email validator, and regular expression url validator.
- Use mysql_real_escape_string() — to escape special characters in a string for use in a SQL statement. It's special characters that are used as the basic tools of database attacks by hackers. It's easy to think your fields' DATA LENGTH will get longer with the escaping in mysql_real_escape_string, pushing end characters into oblivion, but reports are that "I have just experienced that this function does not harm the data length at all. It seems to use the escaped string during insertion but still insert the UNESCAPED string," so perhaps there's magic afoot!
- Use htmlspecialchars() — to convert special characters (& < > " and ') to HTML entities. If you embed strings (i.e., $fname) within HTML markup, you must escape them with htmlspecialchars(). This means that every single echo or print statement should use the htmlspecialchars() function. Always set the ENT_QUOTES argument, so both types of quotes are processed. Note: if you need your strings decoded back to normal, use htmlspecialchars_decode(), again setting the ENT_QUOTES argument. But since htmlspecialchars() is mostly for output, you will not ordinarily need it.
The difference between JavaScript and PHP validation is quite small, but you should do JavaScript form validation if for no other reason than to take the load off the server and distribute it to the client browser (but supplement it with PHP validation whenever you're getting hacker attacks, feeling paranoid, or just like to program). Check it out:
JavaScript:
var ck_email =
/^[A-Za-z0-9-_]+(\.[A-Za-z0-9-_]+)*@([A-Za-z0-9-_]+\.)?([A-Za-z0-9-_]+(\.[A-Za-z]{2,6})(\.[A-Za-z]{2})?)$/;
if (document.form.email.value.search(ck_email)==-1)
{alert("That email address is not valid.");return false}
PHP:
$email = htmlspecialchars($_POST['email'], ENT_QUOTES);
if (!preg_match("/([\w\-]+\@[\w\-]+\.[\w\-]+)/",$email))
{die("That email address is not valid.");}
The above function uses $ before variable names, as all of PHP does. It gets form data POSTed to it, which usually happens. It uses htmlspecialchars() to convert special characters (& < > " and ') to HTML entities, since you may decide to use echo or print statements with the PHP strings gotten from the POST. It uses preg-match(), since that's a popular way to perform a regular expression match in PHP. You may wish to use our more comprehensive regular expression rather than the simple one shown, however.
For preg-match() info.
For htmlspecialchars() info.