How will this affect chances of preventing SQL injection?

SQL Injection Security Issues

  • SQL injection security under php/MySQL. What specific issues do I need to deal with? [more inside] I've done plenty of Google searches, and read several print articles on the topic, but I still feel like I'm missing something. If I validate all user input to make sure quotes are escaped and numeric variables really are numeric, have I closed all the sql injection holes? I think so. Since mysql_query() will only submit one query at a time I'm not too worried about people substituting "id=1;delete from users" for "id=1". Is that a valid assumption? More to the point, should I sleep soundly at night if this is all I'm doing to thwart sql injection under php? function MakeInjectionSafe($string,$mode,$MaxLength) { if (($mode == 'int') and (!is_numeric($string))): $string = 0; else: if ($MaxLength) $string = substr($string, 0, $MaxLength); if (!get_magic_quotes_gpc()) $string = addslashes($string); endif; return $string; } Also, if I'm wrong about this, pretty please don't truncate my database.

  • Answer:

    It may also be worth your while to familiarize yourself with http://dev.mysql.com/doc/mysql/en/GRANT.html. You can basically do a lot of tinkering with them to restrict user access to specific operations on specific columns for specific users from specific hosts. So if you're worried about people messing with your database, you can basically set up a MySQL user that only has insert access, and only has insert access to the table in question, and only from the host that your script is located on, and have your php script connect as that user. My only other tip is to make sure you remember to FLUSH PRIVILEGES every time you change them, or your changes will not take effect.

y6y6y6 at Ask.Metafilter.Com Visit the source

Was this solution helpful to you?

Other answers

Related: where do people find out about what security holes there *are* in PHP, and how to close them? The only one I've ever heard about is this injection attack, and making sure you use $_POST instead of register globals.

gramcracker

MySQL recently implemented support for stored procedures. It's a much better architecture than sending sql strings through commands in web scripts - for lots of reasons including offering better protection against sql injections.

normy

I'm not much of a PHP expert, but I think you'd probably be better off using mysql_escape_string, which is closer to perl's $dbh->quote(), and escapes more than addslashes. gramcracker: Try http://search.securityfocus.com/cgi-bin/swsearch/swish.cgi?query=php&metaname=alldoc&sbm=archive%2F1%2F&start=0.

fvw

http://ask.metafilter.com/mefi/6855#138603 can be a pain to implement at first, but it's a very good practice. If you're limited in the number of user accounts you can create, at least give them strong passwords and the bare minimum of privileges they need to do their jobs. People find security holes by looking for them and by stumbling upon them. I wouldn't think of SQL injection as one attack; it's more like a whole realm you need to be cautious of. Using $_POST instead of making register_globals do the heavy lifting is good, but I always take it a step further and immediately assign the posted value to a variable. That way it's locked away in a cage and can only do what I let it do (so if I'm sloppy and "let" it do something nasty by not preventing that behavior, that's my fault). On preview: stored procs aid security, make things faster and make applications easier to maintain, so now I just have to wait until providers start installing MySQL versions that support them. Anyone have a good reference for MySQL stored proc syntax (other than the manual-- just looking for a favorite bookmark or something)?

yerfatma

yerfatma, not very detailed, but a start http://builder.com.com/5100-6388_14-5178706.html.

normy

alphanerd - Agreed, running your scripts so that you give programmatic access to the DB super user is bad. But probably not helpful in my context. I'm writing something that I want to distribute. Specifically for web logs. A solution that requires bloggers to create special MySQL users may be a non-starter. Sad. But true. If I can lock it down without it that would be much preferred. gramcracker - yerfatma's link #2 is pretty much it. However, it's not php that has security holes, it's the code you write that has security holes. So having a proactive attitude is better than a hard and fast list. normy - Yep. Stored procedures are better. But I'm not using them. Part laziness, part preference. Again, if I can avoid going that route it would make me happier. Part of my problem is that I don't know what I'd fix in a stored procedure that I'm not fixing in the function above. fvw - You are correct sir. Thanks. Part of my problem is that this will be used by people to legitimately add huge blocks of text to the database. And these text blocks may legitimately contain valid SQL.

y6y6y6

Here's what I use, if you're interested. /* Takes a format string and an list of arguments and substitutes the format codes in the format string for the elements of the arguments list. Similar to vsprintf, but specialized for generating SQL queries. Format codes are denoted by a percent sign (%) followed by another character. To insert a literal percent character into the output string, escape it (%%). Each successive format code is replaced by its corresponding argument in the list. %%: Replaced by a literal percent sign. %s: The argument, which must be a string, is used verbatim. %S: Replaced by the argument, which is escaped with addslashes. %q: Use for quoted strings. Like %S, but the value is also surrounded with quote marks. %l: Use for LIKE strings. Like %q, but the _ and % characters are also escaped. %d: The argument, which should be numeric, is used verbatim. Non-numeric arguments will be converted into numbers first. %n: Like %q, but empty strings are replaced with NULL instead of ''. %t: Like %n, but converts the result to a timestamp with FROM_UNIXTIME(). Parameters: 1. The format string. 2+. Any arguments needed by the format string. */ function format($format) { $argument = 0; for ($i = strpos($format, '%'); $i !== false; $i = strpos($format, '%', $i + strlen($replace))) { $value = func_get_arg(++$argument); switch (substr($format, $i + 1, 1)) { case '%': $replace = '%'; --$argument; break; case 's': $replace = $value; break; case 'S': $replace = addslashes($value); break; case 'q': $replace = format('"%S"', $value); break; case 'l': $replace = preg_replace('/([%_\\\'"])/', '\\\\1', $value); break; case 'd': $replace = (int)$value; break; case 'n': $replace = (strlen($value) == 0 ? 'NULL' : format('%q', $value)); break; case 't': $replace = format('FROM_UNIXTIME(%n)', $value); break; default: $replace = ''; } $format = substr_replace($format, $replace, $i, 2); } return $format; } I use it like this: format('SELECT * FROM users WHERE id = %d AND userName = %q AND address LIKE "%%%l%%"', $id, $userName, $city)

Khalad

Aach, I so carefully made sure to indent it properly and blew it on the final click of "Post." Here's the code properly indented. Sorry for taking up so much space on the page! /* Takes a format string and an list of arguments and substitutes the format    codes in the format string for the elements of the arguments list. Similar to    vsprintf, but specialized for generating SQL queries.        Format codes are denoted by a percent sign (%) followed by another character. To    insert a literal percent character into the output string, escape it (%%). Each    successive format code is replaced by its corresponding argument in the list.            %%: Replaced by a literal percent sign.        %s: The argument, which must be a string, is used verbatim.        %S: Replaced by the argument, which is escaped with addslashes.        %q: Use for quoted strings. Like %S, but the value is also surrounded with quote            marks.        %l: Use for LIKE strings. Like %q, but the _ and % characters are also escaped.        %d: The argument, which should be numeric, is used verbatim. Non-numeric            arguments will be converted into numbers first.        %n: Like %q, but empty strings are replaced with NULL instead of ''.        %t: Like %n, but converts the result to a timestamp with FROM_UNIXTIME().            Parameters:      1.  The format string.      2+. Any arguments needed by the format string. */ function format($format) {     $argument = 0;     for ($i = strpos($format, '%'); $i !== false; $i = strpos($format, '%', $i + strlen($replace)))     {         $value = func_get_arg(++$argument);                  switch (substr($format, $i + 1, 1))         {           case '%': $replace = '%'; --$argument;                                        break;           case 's': $replace = $value;                                                  break;                                                                                        case 'S': $replace = addslashes($value);                                      break;           case 'q': $replace = format('"%S"', $value);                                  break;           case 'l': $replace = preg_replace('/([%_\\\'"])/', '\\\\1', $value);          break;           case 'd': $replace = (int)$value;                                             break;           case 'n': $replace = (strlen($value) == 0 ? 'NULL' : format('%q', $value));   break;           case 't': $replace = format('FROM_UNIXTIME(%n)', $value);                     break;                      default:  $replace = '';         }         $format = substr_replace($format, $replace, $i, 2);     }     return $format; }

Khalad

Just Added Q & A:

Find solution

For every problem there is a solution! Proved by Solucija.

  • Got an issue and looking for advice?

  • Ask Solucija to search every corner of the Web for help.

  • Get workable solutions and helpful tips in a moment.

Just ask Solucija about an issue you face and immediately get a list of ready solutions, answers and tips from other Internet users. We always provide the most suitable and complete answer to your question at the top, along with a few good alternatives below.