Follow Slashdot blog updates by subscribing to our blog RSS feed

 



Forgot your password?
typodupeerror
×
PHP Programming Software Apache IT Technology

PHP and SQL Security 305

An anonymous reader writes "PHP and SQL Security are being proven more weak every day. Uberhacker.Com is running a PHP and SQL security research project to raise awareness of secure scripting. The site hosts guides to secure PHP programming, forums, and scripting challenges to see who can create the most secure scripts."
This discussion has been archived. No new comments can be posted.

PHP and SQL Security

Comments Filter:
  • by ArsenneLupin ( 766289 ) on Tuesday April 27, 2004 @10:54AM (#8984047)
    Well, sometimes you can simply blame the tools. Or would you blame the workman who cuts off his arm with the buzz saw's totally unprotected blade?

    Yes, of course. A good workman would never willingly use such a dangerous tool!

    That being said, as far as SQL security goes, PHP fares far better than its competitor, ASP.

    Indeed, by default, PHP comes with gpc_magic_quotes enabled, which prevents the more obvious SQL injection attacks. Of course, nothing is 100% foolproof, but we're nowhere near the sieve that ASP+Sequel Sewer is.

  • by Sanity ( 1431 ) * on Tuesday April 27, 2004 @10:57AM (#8984075) Homepage Journal
    Languages which encourage the mixing of code and data make it extremely easy to write insecure code, and no programmer is immune to bugs. Yes, the coder is to blame, but so is the language.

    SQL is probably the most widespread example of this, closely followed by regular expressions in Perl. I am often amazed that more people aren't working towards programatic ways to express SQL queries and/or regular expressions (attempts exist for both, but rarely make much progress).

  • by JumboMessiah ( 316083 ) on Tuesday April 27, 2004 @11:04AM (#8984188)
    Other than the scripting challenge, what's on this site? I've read the guides to hacking [uberhacker.com], but it's all a bunch of kindergarden material. Seems if you follow the guides you'll certainly have insecure PHP scripts with all kinds of SQL injection. How about posting some real articles on secure PHP scripting...
  • Re:magic_quotes (Score:1, Informative)

    by ArsenneLupin ( 766289 ) on Tuesday April 27, 2004 @11:06AM (#8984214)
    gpc_magic_quotes is intended to protect the novice, non-security aware user. Of course, it will garble the data, but at least it protects the site from being hacked.

    Once our novice gets more knowledgeable, he can convince his admin to remove gpc_magic_quotes setting from his VirtualHost, and use addslashes [php.net] , instead, which allows finer grained operation.

    That way, Peter O'Neill can register with his true name in his Php app.

  • SQL Injection in PHP (Score:5, Informative)

    by uss_valiant ( 760602 ) on Tuesday April 27, 2004 @11:12AM (#8984291) Homepage
    AFAIK SQL injection can be prevented by binding the parameters to the SQL statement and not putting them within SQL.
    An example:
    It's easy to inject some malicious SQL when using the following PHP code:
    mysql_query("INSERT INTO FOO('Bar') VALUES('$some_post_param');");
    But if you prepare the SQL statement with parameters and bind the variable $some_post_param to the statement, it will be secure.
    see mysql manual for mysqli_stmt_bind_param() aka bind_param [php.net]
    $stmt = $mysqli->prepare("INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)"); $stmt->bind_param('sssd', $code, $language, $official, $percent);

    I know this concept from Perl DBI, but in PHP I haven't seen anyone (phpBB, ...) using bind_param. Why is this? Performance? Keeping the code short and simple?

    As for general webserver security: use PHP and perl as cgi, use suEXEC, run the webserver as nobody/www, put the users into chroot jails, but by all means, don't use PHP safe_mode On.
  • Re:magic_quotes (Score:2, Informative)

    by ArsenneLupin ( 766289 ) on Tuesday April 27, 2004 @11:14AM (#8984319)
    You could, but then you piss off all the real programmers on the server who use addslashes() when they need to

    That's why you can enable/disable this setting on a per virtual host or per directory base.

    Leave it enabled from the numbnuts who come straight from the Windows world and can't be bothered about security, and disable it for the more experienced programmers.

    <Directory "/home/site/numbnut">
    php_flag magic_quotes_gpc on
    </Directory>

    <Directory "/home/site/leet_penguin_master">
    php_flag magic_quotes_gpc off
    </Directory>

  • Hoppity Hop (Score:3, Informative)

    by Tablizer ( 95088 ) on Tuesday April 27, 2004 @11:16AM (#8984350) Journal
    and turning off register_globals, will result in better results.

    One of the problems is that PHP has kept changing the way it handles session variables such that if you move your site you may encounter problems (it takes some sites a while to upgrade their PHP interpreter). One solution is to make your own set of session var functions (scalar only) to wrap the changes or per-site differences, or simply live with register_globals on.

    Maybe in a few years it will settle down, but the recent changes have gummed things up for the near future. Every language has had some stupid progressions, and session handling is high on PHP's Stupid List.
  • by dwheeler ( 321049 ) on Tuesday April 27, 2004 @11:17AM (#8984361) Homepage Journal
    For guidelines on how to develop secure programs, see my Secure Programming for Linux and Unix HOWTO [dwheeler.com]. This Free book provides a set of design and implementation guidelines for writing secure programs for Linux and Unix systems. That includes application programs used as viewers of remote data, web applications (including CGI scripts), network servers, and setuid/setgid programs. The book includes specific guidance for a number of languages, including C, C++, Java, Perl, Python, PHP, and Ada95.

  • by shiflett ( 151538 ) on Tuesday April 27, 2004 @11:19AM (#8984391) Homepage

    I have a few articles on my Web site that might be informative: http://shiflett.org/articles [shiflett.org]

    I'm also writing a monthly PHP security column in php|architect [phparch.com], and these articles will be available for free six months after publication.

    Lastly, I am writing PHP Security for O'Reilly, which is due out in the fall.

  • by p3d0 ( 42270 ) on Tuesday April 27, 2004 @11:26AM (#8984472)
    That's exactly the kind of crappy code that makes web sites insecure. If $var includes the right apostrophes, then an attacker can execute pretty much arbitrary SQL code.
  • Re:No. (Score:4, Informative)

    by Anonymous Coward on Tuesday April 27, 2004 @11:27AM (#8984484)
    I regard myself as a fairly competent PHP programmer, and while I wouldn't be surprised if there are security holes in some of the stuff I've written, I've made every effort to stop them from happening.

    I've got a couple of rules I try to abide by - can anyone confirm if they're good programming practice? If they are, then they might prove useful to other people. :-)
    • Always check user input as much as is possible. Probably at least two-thirds of my programming is input data verification.
    • Always escape text which is going into an SQL query, or do an (integer )$number if it's supposed to be an integer. Do this in a very obvious place (eg when setting the $query string itself) so you don't forget. SQL injections are horrid. Test any functions which generate SQL until you're absolutely sure they aren't doing the wrong thing.
    • Use htmlspecialchars() on any text that's being output, to stop users putting rogue HTML, Javascript or anything into the output - even if it'll only end up in an error message or similar.
    • Put database usernames, passwords, pathnames and other similarly important but site-specific data in a define(), where once set it cannot be redefined.
    • Never include() or require() something that isn't a hard-coded string. Use readfile() or fpassthru() or similar if you need to output an HTML template or whatever.
    • Be hugely careful with any file operations. Don't use any user-supplied filenames, etc, unless they're thoroughly checked.
    • Initialise variables, and forcibly set the type of incoming data with an (integer ), (string ) or whatever.
    • Always use $_GET, $_POST etc to get submitted variables and not register_globals, and put anything that's not dealing with getting such data into a function - page_blah( (integer )$_GET['id'], text_unescape( $_GET['moo'] ) ); and so on, in a place neatly out of the scope of any register_globals crap.
    • Never rely on automatic escaping of input variables - I've got a bunch of functions for automatically unescaping arrays and strings which have been mangled by the magic_quotes_gpc rubbish. I'd switch the feature off, but hosts often have it switched on - and my functions check if it is and respond accordingly.
    • Be paranoid. Always assume the user is out to get you. If there's a function which does something restricted but is called by an apparently safe function, double-check the user's credentials.
  • by shiflett ( 151538 ) on Tuesday April 27, 2004 @11:28AM (#8984493) Homepage
    I know this concept from Perl DBI, but in PHP I haven't seen anyone (phpBB, ...) using bind_param. Why is this? Performance? Keeping the code short and simple?

    The reason is that the function you reference is only available in ext/mysqli [php.net], and this requires MySQL 4.1 or greater. There was previously no way to bind parameters like this using PHP and MySQL.

    Also, phpBB is not a good example to use with regard to secure programming practices. It is one of the applications that give people this silly notion that the language is to blame for poor programming.

  • Re:No. (Score:5, Informative)

    by Lumpy ( 12016 ) on Tuesday April 27, 2004 @11:29AM (#8984505) Homepage
    not only purification but treat all incoming data as hostile.

    every thing that comes from the user needs to be scrubbed, bleached, hammered and then finally used when you know it is 100% safe. and it must be used in a safe manner.

    what blows my mind is those that use the DB column name in a webform to be passed.. Oh nice. select from that drop down item_number and simply change it to start playing corrupt the database games.

    Nothing that is ever given to the user, or recieved from the user should be trusted... EVER. that is the first rule and needs to be pounded into everyone in every book about any programming language for the first 5 chapters.

    start there and you will heve very little security issues.
  • Re:Crap site (Score:1, Informative)

    by Anonymous Coward on Tuesday April 27, 2004 @11:34AM (#8984579)
    I'm really really surprised no one else has pointed this out. This is all a bunch of bullshit. This site is not a security site. It is an insane woman who is dillusional. All things should be taken with two pounds of salt. It is a site run by Carolyn P. Meinel. Read more here. [attrition.org][attrition.org]
  • Re:No. (Score:5, Informative)

    by mfh ( 56 ) on Tuesday April 27, 2004 @11:59AM (#8984916) Homepage Journal
    > Always check user input as much as is possible. Probably at least two-thirds of my programming is input data verification.

    Good. You are off to the right start, but with better function programming, you will find yourself writing more feature code than purification code.

    Things to look for:
    • Push 99% of all expected/selectable data into tables with a record_id, so you can easily purify the incoming data:

      function npurify(&$text){
      if(!is_numeric($text)) $text = 1;
      }

      Protects against SELECT SQL injection attacks.

    • Snuff out > and < chars so that they can't contain the Script HTML tag when purifying data. Replacing these characters with their html entities usually works; ie:
      > becomes &gt;
      < becomes &lt;
    • Convert data in your database to base_64 and gzdeflate it:
      $data = base64_encode(gzdeflate($data));
      This will prevent the problems with escaping quotes and apostrophes for SQL, and it will kill any SQL injections in your data.
    • Use better logic for testing incoming data;
      if($this) {perform action}... will limit your chances of having to cope with scipt injections because you are only testing for the existence of a condition, and not the value of the data.
    • Run bitchecking against acceptable alphabets for purification of character values. Gauge to have good CPU usage of this sort of thing.

      // blanks out unaccepted characters
      $alphabet = '`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv wxyz01234567890~!@#$%^&*()_+=-,.<>?/|;:\'"'.chr(92 ).chr(10);
      $sizestr = strlen($text);
      $sizestr--;
      for($i = 0; $i <= $sizestr; $i++) {
      if(strstr($alphabet, $text[$i])) {
      continue;
      }else{
      $text[$i] = ' ';
      }
      }

    • Code a good link converter, so you don't have to accept HTML in posts, and you don't need to accept any HTML.
    • There are likely more, but these are the big ones.

    > Always escape text which is going into an SQL query

    I prefer to write my own SQL text, based on input values. That way you are never using data submitted for the SQL query. The only time they would really submit values would be when they are sending in a username and password, but in that case, you should be extremely stringent in purification by only accepting alphanumeric usernames and passwords (ie: run the alphabet function above, but erase all non-alphanumeric chars from the $ALPHABET var).

    > Use htmlspecialchars() on any text that's being output, to stop users putting rogue HTML

    htmlspecialchars() doesn't always work. I prefer using the example above, by limiting the characters allowed and disallowing HTML in the form of post body/subject data. Converting everything to base64 will make it nearly impossible to script attack the database, too.

    > Put database usernames, passwords, pathnames and other similarly important but site-specific data in a define()

    I disagree, because I use the $_SESSION array instead, which can not be changed by a user if the session cookie is server-side. Sessions can be scooped by sniffers, but that can be managed by your host's security, to prevent it. Certainly change the locale for session data from /tmp/, because that narrows down hack attempts, making it all the more harder to compromise the system.

    > Never include() or require() something that isn't a hard-coded string

    To me, this isn't totally required if you have suitable purification, but that extra bit of paranoia is welcomed, because it shows true fear and that is acceptable in any kind of programming. That sort of humility is welcomed because it demonstrates a compassion for the task at hand.

    > Be hugely care

  • This was modded up? (Score:3, Informative)

    by Backov ( 138944 ) on Tuesday April 27, 2004 @12:08PM (#8985052)
    PHP hasn't executed more than one query per mysql_query() for quite some time. Your exploit example might have worked a few years ago, but not for some time.

    PHP/MySQL is not really that unsecure. If you don't do stupid things, you won't (generally) get hacked.
  • by slamb ( 119285 ) * on Tuesday April 27, 2004 @12:23PM (#8985253) Homepage
    Indeed, by default, PHP comes with gpc_magic_quotes enabled, which prevents the more obvious SQL injection attacks. Of course, nothing is 100% foolproof, but we're nowhere near the sieve that ASP+Sequel Sewer is.

    No, no, no, no, no!

    magic_quotes_gpc is totally broken. For those unfamiliar, it escapes all HTTP GET and POST strings MySQL-style. But this is stupid. How you want your strings escaped (if you do at all!) depends on where you are sending them to, not where you are getting them from. Consider these things you might be doing with the strings:

    • using in a database statement (DML or query) with bind variables: no escaping. (This is the best way to use these in SQL!)
    • sending them out as character data in a HTML page: escape & to &amp;, escape < to &lt;, and (when in an attribute, harmless otherwise) escape " to &quot;
    • using in a MySQL or PostgreSQL literal: that way is actually correct
    • using in a MySQL or PostgreSQL identifier: that might also be correct? not sure. certainly " needs to be escaped, though.
    • using in a standard SQL literal: ' needs to be escaped to ''. \ should not be escaped.
    • using in a standard SQL identifier: " needs to be escaped to "". \ should not be escaped.

    PHP has a shiny red button that you never want to press. This is one of many reasons that I say PHP is a broken tool.

  • by slamb ( 119285 ) * on Tuesday April 27, 2004 @12:59PM (#8985737) Homepage
    Most people are attempting to solve cross-site scripting and SQL injection vulnerabilities (the #4 and #6 causes of web security problems, according to this article [lwn.net]) through brute force. Everywhere they use these, they use an escaped version. But this approach doesn't work! For several reasons:
    • it's hard to notice when something is not there.
    • people tend to push these farther and farther away from the actual usage, so they get confused about what has been escaped. It's hard to maintain clear contracts between functions about something like this.
    • even if you're diligent when writing the initial code, it's easy to slip when applying patches

    So I think a new approach is needed. One where you don't mix instructions and data so easily, or flag them more readily.

    With SQL, this has been around for a while: bind variables. Your SQL queries tend to be static with ? thrown in (or :foo for named bind variables). In Perl, it looks like:

    my $sth = $dbh->prepare('select * from mytable where foo = ?');
    $sth->execute($foo);

    Not everyone is using bind variables, and I don't know why. One reason may be that positional bind variables can be confusing: they require you to correlate two lists in your head to position the correct variables in the correct spots. Not all language/database combos support named bind variables. (JDBC doesn't!) But they can be emulated - that's one reason I made xmldb [slamb.org].

    For HTML, it's more rare to find something that does this. Apache Cocoon does, but it's grotesquely complex. I'm working on a simpler system [slamb.org], though it's not ready for production. Here's the idea: my files (XFP) are to a SAX ContentHandler [sun.com] as JSP is to a byte stream.

    I like SAX because it's a way of making XML that does things right. Instead of doing something like:

    out.println("<elem a=\"" + foo + "\" b="blah">Blah: " + bar + "</elem>");
    you write something like:
    AttributesImpl attribs = new AttributesImpl();
    a.add("a", foo);
    a.add("b", "blah");
    out.startElement("elem", a);
    out.characters("Blah: " + bar);
    out.endElement("elem");
    it's nice in that you don't do any of the escaping yourself - you just tell it how you're using each string, so it can do the escaping right. But that's six ugly lines instead of one, and it's worse with real SAX because you need extra arguments for namespaces and things. So I looked at JSP. It sticks Java code inside the text to produce. I stick Java code inside the XML to produce. I write something like this:
    <elem b="blah">
    <xfp:attribute name="a">foo</xfp:attribute>
    Blah: <xfp:expr>bar</xfp:expr>
    </elem>
    ...and it turns it into the code above when it makes a .java file. It still knows how to escape things from context. And whenever you stick in literal text, you can write it just like you'd normally write XML - less long-winded. I might change it to this:
    <elem a="{foo}" b="blah">Blah: {bar}</elem>
    which is shorter still.

    My code is all Java. But the concepts should apply to PHP, Perl, Python, anything.

    Anyone else working on a system to solve this problem? I'd be interested to share ideas.

  • Re:Crap site (Score:2, Informative)

    by karkle ( 64159 ) on Tuesday April 27, 2004 @01:32PM (#8986216) Homepage

    There is a good guide available not specifically for PHP, but general secure web developement. I'm not the author and don't know where to link to his site or the latest guide but here's a mirror of it.

    Best Practices for Secure Web Development [mkaz.com] By Razvan Peteanu

  • by mabu ( 178417 ) on Tuesday April 27, 2004 @01:48PM (#8986416)
    Being a low-level programmer, and specifically working on advanced CGI, awhile back I bowed to pressure to offer some of my web clients scripting abilities on their servers. I went with PHP/MySQL and started the process of learning about the language and its caveats.

    The first thing that completely freaked me out was the register_globals setting in PHP. I invited a PHP programming friend to come hang out and give me a little intro-tutorial into how he developed so that I could understand where these guys were coming from when developing apps. He proceeded to show me this "neat feature" called register_globals that makes it super easy to access passed parameters from the outside world. Of course it also makes it super easy for anyone on the planet to overload internal variables that could be used just about anywhere in the scripts. I've never seen such a dangerous "feature" [in a non-Microsoft product].

    And this all ties into the number one rule of programming. When you're coming from C/C++, 80% of your job involves data/input validation, so it's second nature to cover your ass. I found myself very confused at first over the dozens of different functions available to escape, unescape, tokenize and otherwise mangle input from/to various forms. No wonder developers are confused.

    But above all, there are basic tenets that the server admin should enforce that have the most impact on security. First off, NOBODY should be enabling register_globals - it's just a crutch for crappy programmers IMO. Second, safe_mode is a must. If you have an app that needs safe_mode to be disabled, then you are better off isolating that app to its own private server. Third, every application should have its own private database work area. I am amazed at developers who run multiple applications in a single database space. Fourth, the configuration of the web server needs to be such that PHP code is properly protected, with .htaccess restrictions in code lib directories and careful consideration over other virtualhosts that might have php disabled in a higher-level directory.

    Safe_mode is a good tool. It also creates annoyances for the customers, especially those who are writing apps that create files in their work area... this requires the admin's intervention to set up the proper permissions (and gives them a chance to give the client code a once-over for glaring errors).

    One thing I haven't quite figured out, and maybe I just need the proper Apache mod, but when a PHP app creates a file, it's owned by the web process and not the script user process, so in safe_mode, to get things working you either have to change permissions or give liberal directory permissions in order for things to work with user-uploaded code.

    Ultimately, the server admin should bit the bullet and refuse to give users access to certain dangerous "features" such as register_globals or non-safe_mode. It's just too easy to open a Pandora's box.
  • Re:array[key] (Score:2, Informative)

    by B3ryllium ( 571199 ) on Tuesday April 27, 2004 @02:22PM (#8986811) Homepage
    bzzt, sorry, you are incorrect (sort of :)) ... the safest way to perform that in a string is as follows:
    print ("{$array['key']}");
    Sure, it's ugly. But it works for objects, too:
    print ("{$item->getValue('Ham!')}");
    Anyway. La la la la la la ...
  • Re:Bind variables (Score:3, Informative)

    by fungus ( 37425 ) on Tuesday April 27, 2004 @03:11PM (#8987582)
    Not only bind variables are more secure, but they also increase database performance where it counts.

    Bind variables permit databases to match a query with cached queries even if parameters are different. It will then be able to fetch the appropriate execution plan instead of making a new one for each similar request.
  • by Anonymous Coward on Tuesday April 27, 2004 @05:34PM (#8989777)
    Just use SafeSQL [phpinsider.com], a database wrapper class that handles SQL injection very easily, among other very useful features. This one is a must-have for any PHP/SQL application IMHO.

  • Re:array[key] (Score:2, Informative)

    by kuzb ( 724081 ) on Tuesday April 27, 2004 @09:03PM (#8991968)
    to maintain consistancy, you can also use {} when interpolating complex variable types.

    ex: echo "blah blah {$array['key']} blah blah";

    it's bad to use $array[key]; outside of interpolation though, because PHP will first look for a constant called 'key' before it decides you're using a string. if you have a defined constant named 'key' it will use that first, which may not be desierable.

You knew the job was dangerous when you took it, Fred. -- Superchicken

Working...