/    Sign up×
Community /Pin to ProfileBookmark

Is this adequate form-field security?

Every form field on our site I have running through this function; is this adequate protection from SQL injection and spam-hijacking? Or am I missing something crucial?

[code=php]
function field_sanitize_basic($input) {
if (!is_array($input))
{
$input = array($input);
}

$gobbledegook_alphabet = array(‘passwd’,’password’,’Bcc’,’mime’,’Content-Type’,’¡’,’¢’,’¤’,’|’,’§’,’¨’,’ª’,’«’,’¬’,’®’,’¯’,’°’,’±’,’²’,’³’,’µ’,’¶’,’·’, ‘¸’,’¹’,’º’,’»’,’¼’,’½’,’¾’,’¿’,’À’, ‘Á’,’Â’,’Ã’,’Ä’,’Å’,’Æ’,’Ç’,’È’,’É’,’Ê’,’Ë’,’Ì’,’Í’,’Î’,’Ï’,’Ð’, ‘Ñ’,’Ò’,’Ó’,’Ô’,’Õ’,’Ö’,’×’,’Ø’,’Ù’,’Ú’,’Û’,’Ü’,’Ý’,’Þ’,’ß’, ‘à’,’á’,’â’,’ã’,’ä’,’å’,’æ’,’ç’,’è’,’é’,’ê’,’ë’,’ì’,’í’, ‘î’,’ï’,’ð’,’ñ’,’ó’,’õ’,’ö’,’÷’,’ø’,’ú’, ‘û’,’ü’,’ý’,’þ’);

foreach($input as $key => $valueold){

foreach($gobbledegook_alphabet as $value2) {
if (stristr($valueold, $value2) !== false) {
$valueold = $input[$key] = str_ireplace($value2, ‘*’, $valueold);
$_SESSION[‘field_sanitize_basic_warning’] = ‘<p class=”note_bold”>Some potentially unsafe text in your submission was removed!</p>’;
}
}

$valueold = htmlspecialchars($valueold);
$valueold = stripslashes($valueold);
$valueclean = $valueold;
$value = $input[$key] = $valueclean;
}
return $input[0];
}
[/code]

(Oh, the whole doing the input and return as an array, is because I’m working on returning errors and the like — ignore some oddness about that part. I’m just curious right now about the actual security/substitution stuff.)

Thanks for any feedback!
Liam

to post a comment
PHP

6 Comments(s)

Copy linkTweet thisAlerts:
@NogDogNov 30.2010 — htmlspecialchars() is for escaping [i]output[/i], not validating input (IMHO).

stripslashes() should only be used if you need to undo the "damage" of magic_quotes_gpc(). You can test for it via get_magic_quotes_gpc() in an if() condition to determine if you need to apply it -- or just make sure you have magic_quotes_gpc turned off on your system so you don't have to worry about it.

Those characters you are stripping out might be annoying at times, but should not be dangerous in and of themselves. And what happens if someone from, say, France wants to sign up on your site and has a name like "André" or "François"? Are you going to register them as "Andr" and "Franois"? The only characters I'd consider stripping out in all cases are nulls,possibly newlines/carriage-returns (except in textarea fields), and maybe some of the control characters at the start of the ASCII codes (i.e., everything less than decimal code 31 (space), excluding anything like tab or newline that you want to allow).

The [i]only[/i] thing that is required to prevent SQL injection is the proper use of the applicable escaping mechanism for the DB extension being used, or else prepared statements with place-holders and bound parameters (for DB extensions that support prepared statements).
Copy linkTweet thisAlerts:
@mechphistoauthorNov 30.2010 — Oops.

I messed up. This example is one for forms in which the results are sent via e-mail and are displayed on the Web page -- not for MySQL inserts, which is what I indicated when I said "SQL injection."

To be clear, EVERY form field goes through this process above, but what I didn't say was that EVERY form field that gets used in a SQL query ALSO goes through a mysql_real_escape_string() before inclusion in the query.

Sorry. Thanks!
Copy linkTweet thisAlerts:
@mechphistoauthorNov 30.2010 — htmlspecialchars() is for escaping [i]output[/i], not validating input (IMHO).

[...]

Those characters you are stripping out might be annoying at times, but should not be dangerous in and of themselves.

[...]

The only characters I'd consider stripping out in all cases are nulls,possibly newlines/carriage-returns (except in textarea fields), and maybe some of the control characters at the start of the ASCII codes (i.e., everything less than decimal code 31 (space), excluding anything like tab or newline that you want to allow).

[...]

.[/QUOTE]


OK, so I changed it to:

[code=php]
function field_sanitize_basic($input) {
if (!is_array($input))
{
$input = array($input);
}

$removal_list = array('passwd','password','Bcc','mime','Content-Type');

foreach($input as $key => $valueold){

foreach($removal_list as $value2) {
if (stristr($valueold, $value2) !== false) {
$valueold = $input[$key] = str_ireplace($value2, '*', $valueold);
$_SESSION['field_sanitize_basic_warning'] = '<p class="note_bold">Some potentially unsafe text in your submission was removed!</p>';
}
}

$valueold = htmlspecialchars($valueold);
if (get_magic_quotes_gpc()) {
$valueold = stripslashes($valueold);
}
$valueclean = $valueold;
$value = $input[$key] = $valueclean;
}
return $input[0];
}
[/code]


(And, again, I'm using mysql_real_escape_string() on every field that gets used in a SQL querey.)

So, how do I remove certain dec characters below 31? Do I just, say, if I wanted to remove nulls and line feeds, change the array to:

$removal_list = array('passwd','password','Bcc','mime','Content-Type', '0x00', '0x10');

I don't think I'm right about that. I did some Googling, and can't find anything except, at best:

$text = str_replace("", "", $text);

to remove a null. But I don't know Perl, and have no idea what the less-than 31 dec's are in Perl-speak.

Thanks for your advice!

Liam
Copy linkTweet thisAlerts:
@NogDogNov 30.2010 — OK, so it's a slow day:
[code=php]
<?php
/**
* Clean up inputs
*/
class Cleaner
{
/**
* @var array List of things to get rid of
*/
private $replace = array();
/**
* @var string The regular expression that will be used
*/
private $regexp = '//';
/**
* Add a string to the list and regexp
* @return object
* @param string $value
* @param bool $escape Apply preg_quote if true
*/
public function addReplace($value, $escape = true)
{
$this->replace[] = ($escape) ? preg_quote($value) : $value;
$this->regexp = '/(' . implode('|', $this->replace) . ')/i';
return $this;
}
/**
* Do the replacement
* @return void
* @param string $string (Passed by reference so array_walk() can use)
* @param string $key (optional)
*/
public function replace(&$string, $key=null)
{
$string = preg_replace($this->regexp, '', $string);
}
}

// sample usage
$badStuff = array(
'<code>',
'foo',
'bar'
);
$cleaner = new Cleaner();
$cleaner->addReplace('[x00-x1F]', false); // don't escape this
foreach($badStuff as $bad) {
$cleaner->addReplace($bad); // do escape these
}
array_walk_recursive($_GET, array($cleaner, 'replace'));
?>
<p><a href='?test=ok%20foo%20bar%20ok&foo=a%00b%11c'>click me</a></p>
<?php
echo "<pre>" . print_r($_GET, 1) . "</pre>";
[/code]

?
Copy linkTweet thisAlerts:
@mechphistoauthorNov 30.2010 — Bwah! Object-oriented PHP? That's witchcraft, I tells ya! ?

Seriously, though, I'm ashamed to admit I started learning PHP before OO, so I've been woefully reticent to try anything in that way. ?

But this looks rather bleepin' cool and useful! I'll give it a good and thorough look-see.

Thanks!!

Liam
Copy linkTweet thisAlerts:
@NogDogNov 30.2010 — Yeah, it just seemed more efficient to me than creating a single function that would have to rebuild the regexp each time it was called, or else have to write multiple separate functions.
×

Success!

Help @mechphisto spread the word by sharing this article on Twitter...

Tweet This
Sign in
Forgot password?
Sign in with TwitchSign in with GithubCreate Account
about: ({
version: 0.1.9 BETA 6.2,
whats_new: community page,
up_next: more Davinci•003 tasks,
coming_soon: events calendar,
social: @webDeveloperHQ
});

legal: ({
terms: of use,
privacy: policy
});
changelog: (
version: 0.1.9,
notes: added community page

version: 0.1.8,
notes: added Davinci•003

version: 0.1.7,
notes: upvote answers to bounties

version: 0.1.6,
notes: article editor refresh
)...
recent_tips: (
tipper: @meenaratha,
tipped: article
amount: 1000 SATS,

tipper: @meenaratha,
tipped: article
amount: 1000 SATS,

tipper: @AriseFacilitySolutions09,
tipped: article
amount: 1000 SATS,
)...