Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is preg_match safe enaught in input satinization?

I am building a new web-app, LAMP environment... I am wondering if preg_match can be trusted for user's input validation (+ prepared stmt, of course) for all the text-based fields (aka not HTML fields; phone, name, surname, etc..).

For example, for a classic 'email field', if I check the input like:

$email_pattern = "/^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)" .
    "|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}" .
    "|[0-9]{1,3})(\]?)$/";

$email = $_POST['email'];
if(preg_match($email_pattern, $email)){
    //go on, prepare stmt, execute, etc...
}else{
    //email not valid! do nothing except warn the user
}

can I sleep easy against the SQL/XXS injection?

I write the regexp to be the more restrictive as they can.

EDIT: as already said, I do use prepared statements already, and this behavior is just for text-based fields (like phone, emails, name, surname, etc..), so nothing that is allowed to contain HTML (for HTML fields, I use HTMLpurifier).

Actually, my mission is to let pass the input value only if it match my regexp-white-list; else, return it back to the user.

p.s:: I am looking for something without mysql_real_escape_strings; probably the project will switch to Postgresql in the next future, so need a validation method that is cross-database ;)

like image 935
Strae Avatar asked Apr 12 '10 14:04

Strae


People also ask

What is the return value of the preg_match() method?

preg_match() returns 1 if the pattern matches given subject, 0 if it does not, or FALSE if an error occurred.

What are the PHP’s preg_match () parameters?

PHP’s Preg_match () functions usually works is based on the five parameters included inside of the preg_match () function. Given below are the parameters: 1. Pattern Parameter: This is the PHP’s preg_match ()’s parameter which is used to hold the pattern to search the string as a string.

What is the difference between $matches and Preg_offset_capture?

matches: If matches exists then it contains results of search. The $matches [0] will contain the text that matched full pattern, $matches [1] will contain the text that matched the first captured parenthesized subpattern, and so on. PREG_OFFSET_CAPTURE: If this flag is passed, for every match the append string offset will be returned.

What is the use of emptypreg_unmatched_as_null?

PREG_UNMATCHED_AS_NULL - When this option is enabled, unmatched subpatterns will be returned as NULL instead of as an empty string. Optional. Defaults to 0. Indicates how far into the string to begin searching. The preg_match () function will not find matches that occur before the position given in this parameter


2 Answers

Whether or not a regular expression suffices for filtering depends on the regular expression. If you're going to use the value in SQL statements, the regular expression must in some way disallow ' and ". If you want to use the value in HTML output and are afraid of XSS, you'll have to make sure your regex doesn't allow <, > and ".

Still, as has been repeatedly said, you do not want to rely on regular expressions, and please by the love of $deity, don't! Use mysql_real_escape_string() or prepared statements for your SQL statements, and htmlspecialchars() for your values when printed in HTML context.

Pick the sanitising function according to its context. As a general rule of thumb, it knows better than you what is and what isn't dangerous.


Edit, to accomodate for your edit:

Database

Prepared statements == mysql_real_escape_string() on every value to put in. Essentially exactly the same thing, short of having a performance boost in the prepared statements variant, and being unable to accidentally forget using the function on one of the values. Prepared statement are what's securing you against SQL injection, rather than the regex, though. Your regex could be anything and it would make no difference to the prepared statement.

You cannot and should not try to use regexes to accodomate for 'cross-database' architecture. Again, typically the system knows better what is and isn't dangerous for it than you do. Prepared statements are good and if those are compatible with the change, then you can sleep easy. Without regexes.

If they're not and you must, use an abstraction layer to your database, something like a custom $db->escape() which in your MySQL architecture maps to mysql_real_escape_string() and in your PostgreSQL architecture maps to a respective method for PostgreSQL (I don't know which that would be off-hand, sorry, I haven't worked with PostgreSQL).

HTML

HTML Purifier is a good way to sanitise your HTML output (providing you use it in whitelist mode, which is the setting it ships with), but you should only use that on things where you absolutely need to preserve HTML, since calling a purify() is quite costly, since it parses the whole thing and manipulates it in ways aiming for thoroughness and via a powerful set of rules. So, if you don't need HTML to be preserved, you'll want to use htmlspecialchars(). But then, again, at this point, your regular expressions would have nothing to do with your escaping, and could be anything.

Security sidenote

Actually, my mission is to let pass the input value only if it match my regexp-white-list; else, return it back to the user.

This may not be true for your scenario, but just as general information: The philosophy of 'returning bad input back to the user' runs risk of opening you to reflected XSS attacks. The user is not always the attacker, so when returning things to the user, make sure you escape it all the same. Just something to keep in mind.

like image 179
pinkgothic Avatar answered Oct 30 '22 14:10

pinkgothic


For SQL injection, you should always use proper escaping like mysql_real_escape_string. The best is to use prepared statements (or even an ORM) to prevent omissions. You already did those.

The rest depends on your application's logic. You may filter HTML along with validation because you need correct information, but I don't do validation to protect from XSS, I only do business validation*.

General rule is "filter/validate input, escape output". So I escape what I display (or transmit to third-party) to prevent HTML tags, not what I record.

* Still, a person's name or email address shouldn't contain < >

like image 30
instanceof me Avatar answered Oct 30 '22 15:10

instanceof me