Forum Moderators: coopster
I've got a project spec that requires an online guest book where the public can - of course - leave comments. I'm deathly afraid of what spam bots and malicious individuals could do to my client's database so I've already put the following security measures into place:
Captcha, hidden email form field (if this field is populated on POST it's obviously a bot), use of mysql_real_escape_string before database insertion.
Is this enough? Are there other layers of protection that I should use? Obviously the most important issue to me is to protect my client's database.
I've also read on other forums that Captcha's may or may not still be so useful as - according to some forum posters - some bots have become much more adept at deciphering image-based codes.
Any and all guidance greatly appreciated.
Neophyte
you can use regular expressions to filter unwanted characters of your data
hide php errors in final project, either from php ini or from htaccess (whichever you have access to)
register globals off at all times
if i think anything else i will post it
If you allow the guest book pages to be crawled, you can use a robots <meta> tag set to "nofollow" on those pages or insert rel="nofollow" into all <a>nchor tags in user submissions to discourage SPAMming.
Accept only what you want for input and throw everything else away. That is, don't "look for" bad data (at first,) only accept what you want, removing ALL non-punctuation characters, accept only the ASCII set on your language.
Then you can go on to filter for patterns. Some top hitters are
b*cc\s*: - make it case insensitive; this is an attempt to inject a bcc or cc header.
content\-type - attempt to create a multipart email
[\s*URL.*\]*
[\s*LINK.*\]*
[\s*a\s*href.*\]*
<\s*a\s*href.*\>*
yourdomain.com
and so on. A common attack is to inject anything@yourdomain.com into a mailer and keep doing so until one is accepted (dictionary attack.) - you would rarely need to submit a form from your own company.
Guest book = moderate EVERYTHING. Do not make the posts live immediately.
If you use mailers in the submission, lock them down, make sure they are not vulnerable to header injection. Lots of threads on this. Also if you DO have a mail function and it sends to the poster, make sure that email comes "from" a no-reply address. Many spammers will submit your form just to get at your real email.
Do not use exec/system commands in your scripts that execute external processes. There are safe ways to do this, but if you don't know them, find another way. In fact, find another way anyway and use exec/system as a last resort - the fewer technologies you involve, the fewer risks of opening a security hole.
If you use a database of any sort, do not replicate field names in your forms. Any clue you give can be pieced together. An easy way to do this is set up a simple array of aliases for forms and table names. For example, table field names on left, form element names on right:
$fields = Array (
'email_address' => 'email',
'first_name' => 'fname'
);
Turn error reporting off.
Be cautious in what error message are displayed directly from your script. For example, in a login (which you're not using, follow along,) don't say "Invalid email address" or "invalid password" say "login failed". "Well we have the email now, let's hack the password . . . "
Along those lines, after debugging, kill any API generated errors. This
$result=@mysql_query("$select");
if (!$result) { die("Error " . mysql_error()); }
can reveal information about your database (which you WANT in development) but can give hackers clues where to look. Instead,
$result=@mysql_query("$select");
if (!$result) { die("could not write to database, please contact us"); }
There are likely to be more, and some are specific to the application itself. Guestbooks are the most attacked forms, I think, second only to mailer forms.
You could also put the guestbook in a separate database, or even in a separate subdomain, to further insulate it from the other parts of the website.
Thanks very much for all of your guidance - invaluable!
Rockinbil: when you're talking about filtering for patterns such as [\s*URL.*\]*, b*cc\s*, etc., what do the brackets, asterisks and backslashes refer to in your examples? Are these (i.e. '[\s') part of what I should look for when filtering?
Neophyte
The backslashes escape characters that take on a different meaning within most programming languages, including PHP.
\[\s*URL.*\]* (corrected)
\[ and \] = the brackets entered in form input, often used by link spammers to drop BBcode forum links - even in email. Without the \, this defines a regexp character class.
\s = any white space, but without it it means the letter s.
* means zero or more, so adding white space between characters doesn't get around your filters.
. means "any character;" with a backslash, \. it would mean a literal period.
So the above would be used like
$fieldUsed = '';
$bad_patterns = Array (
'b*cc\s*:',
'content\-type',
'\[\s*URL.*\]*',
'\[\s*LINK.*\]*',
'\[\s*a\s*href.*\]*',
'\<\s*a\s*href.*\>*',
'yourdomain.com'
);
foreach ($_POST as $key=>$value) {
foreach ($bad_pattern as $pattern) {
if (preg_match("/$pattern/i",$value)) {
//You should already be logging input for review
// later, but here you set $fieldUsed so when done
// it will exit with a short message:
//Malicious input found
$fieldUsed .= "used field $key for spam pattern $value";
}
}
}
if ($fieldUsed != '') {
// Exit with short msg here
}
Note the case-insensitive modifier, i, after the regexp delimiter, this is important (BCC or bcc, URL or url, etc.)