PHP Web Application Security: Backend

This is a sticky topic.
  • Filter
  • Time
  • Show
Clear All
new posts

    important PHP Web Application Security: Backend

    There's a lot of things to be considered when building a php application, the architecture, target audience, coding styles, environment etc. but one of the most important thing to consider is security. Exploiting a web site is fun (except its yours being exploited) but warding off potential exploits is more satisfying! I know there are tons of tutorials on how to protect your web site but most are bloated and contain unnecessary info. So I will take my time to explain in ridiculously simple English how to protect your php application. Please note that this does not cover exploits related to servers etc. just php programming.

    The Environment

    Before starting any project it's very essential that you know your php environment. There are many configurations possible in php servers but for the sake of simplicity I will focus on the ones that are most popular and affect most php developers.

    1. Magic Quotes
    Magic Quotes is a php setting that automatically escapes (adds a single backward slash) to a string that contains special MySQL characters like the single quote ('), and double quote ("). This is a well-meaning rubbish setting to have on because it's not effective in covering the exploit (SQL injection) it was originally intended to cover. This directive needs to be disabled before anything (more on that later), why? Because we have a better way of covering the exploit and too many cooks spoil the broth.

    2. Register globals
    Now this is yet another well meaning crap feature of php that has thankfully been disabled by default in new releases of php. What this does is register variables from GLOBALS like GET, POST, REQUEST. While I'm not going to go into details about why it's nasty, we do need to make sure it's disabled, trust me on this.

    Now that we have identified what has to go, how do we make it go? There are many ways of disabling these directives, the easiest is if you have access to your servers php.ini configuration file, but most don't so I won't go into that. I want to assume the readers just have access to pure php code

    PHP Code:
     * Disabling magic quotes
     * @see

    // Sanitize the PHP variables
    $_GET app_sanitize($_GET);
    $_POST app_sanitize($_POST);
    $_COOKIE app_sanitize($_COOKIE);

    // it's not a good practice to use $_REQUEST variable so stay away
    $_REQUEST array_merge($_GET$_POST);

    // We want to be able to recursively sanitize array values
    if (is_array($value))
    // Hold new array data
    $_value = array();

            foreach (
    $value AS $key => $val)
    // Recursively sanitize array value
    $_value[$key] = app_sanitize($val);

    // Return the sanitized array
    return $_value;
        elseif (
    // Check if magic quotes is enabled on the server
    $magic_quotes = (bool) magic_quotes_gpc();

            if (
    $magic_quotes === TRUE)
    // Strip slashes that magic quotes may have put there
    $value stripslashes($value);

    // You may choose to add some additional sanitization here or not its a free world...

    return $value;

    Then for the other misdemeanour called register globals...

    PHP Code:
     * Unregister globals. Disables the evil effect of register globals...
     * @see
    function app_unregister_globals()
        if (
    // Globals array to disable
    $array = array('_REQUEST''_SESSION''_SERVER''_ENV''_FILES''GLOBALS''_COOKIE');

            foreach (
    $array AS $value)
                foreach (
    $GLOBALS[$value] as $key => $var)
                    if (
    $var === $GLOBALS[$key])
    // Remove the unwanted code

    // Call the unregister function, typically at the beginning of every php page
    Okay so now we have a nice clean slate to work with. There are other environments to cater for but we'll just work with these for now. Please remember that after disabling magic_quotes, YOUR APPLICATION IS VIRTUALLY OPEN TO EXPLOITS, especially for those accessing data from a database. In the course of this tutorial though, we will talk about how to essentially, establish that exploit covering in a better way.
    Last edited by CreativityKills; 15.07.12, 08:59. Reason: Code and Typography changes


      Okay so last time we disabled magic_quotes and register_globals. While disabling register globals does not have any effect on our coding (except you did it for an existing script that requires register_globals to be on, in which case im truly sorry for you), disabling magic_quotes_gpc DOES have an effect on our security. First, we just told php: 'Hey, we want to handle our data escaping ourselves okay?!' therefore PHP has stopped trying to help out, now its left to YOU to implement some escaping mechanism when submitting user data to the mysql database engine (there are other database engines that i will not cover but you can do well to google that).

      Problem: How to sanitize data while querying database...
      Exploit: MySQL injection [See: ]

      Since, we have to escape data passed to mysql to avoid confusing mysql, and we have disabled the php mechanism that "did" that for us, how do we effectively protect ourselves... One function... mysql_real_escape_string. This function really escapes data submitted into MySQL, thus avoiding confusing the engine.

      Im going to stop for a moment and say this, I am again assuming everyone reading this ALREADY KNOW what the adverse effects of MySQL injection is, and also have at least intermediary knowledge of PHP.

      ...SO back to the tutorial. Using mysql_real_escape_string will effectively protect you from database injection. Yes, just that and proper coding practise is usually enough.

      PHP Code:
       * Using PHP mysql_real_escape_string on $_GET
       * Lets say the request uri is'hello+there+whats+up+loser'

      // Get the message from $_GET
      $message = isset($_GET['message']) ? $_GET['message'] : NULL;

      // Database insert, SAFE...
      mysql_query("INSERT INTO `some_table` (`some_column`) VALUES(' "mysql_real_escape_string($message) ." ')");

      // Database insert, NOT SAFE...
      mysql_query("INSERT INTO some_table (some_column) VALUES($message)"); 
      Here we have two instances, both inserting message gotten from a variable to the database. You can try them out in your local host to see the difference in performance and results. One executes smoothly, and the other well, does not. I'm not going to say anything regarding the dangers, im just telling you the proper ways to do things.

      On the side note, you may be wondering why i did that conditional before retrieving my $_GET data? Well its simple, if the $_GET array has the key 'message' it retrieves it, else it produces a default value. Imagine it doesnt have a 'message' key and we used just $message = $_GET['message'] to try to set it? Yes, PHP will throw a E_NOTICE index not defined error which will look bad. So checking is a good coding practice.

      Another side note is the proper way of writing SQL statements, while it seems unnecessary, its a very good security plus to write proper SQL statements. Always putting data in the right quotes helps. While its not important, as MySQL is smart, its a good practise. Examples below...

      PHP Code:
       * I always like to compose my sql and store in a variable before  doing anything on it.
       * Remember to always  sanitize your variables before adding to the SQL statement.
       * I did not do it for simplicity sake.

      // Good SQL statements...
      $sql "SELECT * FROM `some_table` WHERE `id`= ' "$some_id ." ' ";
      $sql "INSERT INTO `some_table` (`some_column`, `another_column`) VALUES( ' "$one ." ', ' "$two ." ' )";
      $sql "DELETE FROM `some_table` WHERE `another_column`= ' " $one_column " ' ";

      // Bad SQL statements...
      $sql "SELECT * FROM some_table WHERE id= $some_id"// No quotes, potential security flaw...
      $sql "INSERT INTO some_table (some_column, another_column) VALUES('$one','$two')"// No quotes surrounding table and column name, not important but it wont kill you
      $sql "DELETE FROM `some_table` WHERE `another_column`= $one_column "// No quotes surrounding the inserted variable, Big no no! 
      Added after 11 minutes:

      Coding practices is actually the main reason you are getting your application exploited. Lets go over some useful coding practices. This is perhaps the most important piece of advice you'll get...ever. When dealing with ANYTHING you are not generating, take it as untrusted and it could harm your application. PERIOD! Having this mindset can help you protect even when it seems its not needed.

      Variable typecasting. Simply put, it ENFORCES a certain data type to be used. Im going to use the most practical example of typecasting.

      Case: we want to retrieve an ID to identify a particular product.
      Facts: The ID is always an integer.
      Problem: Its submitted by user, so its unsafe!
      Solution: make sure the data submitted is always an integer, we don't need any other type.

      PHP Code:
       * Lets say the URL is: http://' OR 1 = 1
      $id = isset($_GET['id']) ? $_GET['id'] : NULL;

      // without typecasting...
      echo ''The value of id is'.$id; // This outputs: The value of id is: ' OR 1

      // with typecasting
      $id = (int) $id;
      'The value of id is: '.$id// This outputs: The value of id is: 0 
      See the difference that bit of code made in the script? even with no quote escaping, its perfectly safe to insert $id into database for querying, because as long as its not an integer, it will return 0. Always recognizing and filtering data can help protect your site from attacks. There are other types of type casting methods like (string), (bool) etc, but thats for your personal research, im just alerting you to the possibilities.

      Added after 16 minutes:

      Another often overlooked security practice is database schema. Yes, database schema. How this helps? Structuring your database is VERY important. We dont want any data that shouldnt be there to be there, ever.

      After your usual program side filtering, its always nice to add a bit of mysql filtering. How you ask? Lets just say we want to build a simple database table for our users.

      Case: Plan the schema of our users table
      Fact: we want four columns (id,username,password,biography)
      Problem: We dont want incompatible data submitted
      Solution: proper database schema planning

      First we want to look at each column individually. The 'id' column, we want this to be an auto incrementing integer that is the primary key for fetching data in the table and so it has to be unique (no two columns can have the same id). Next, the username column, we want the usernames to generally have at most 15 characters, and we want this UNIQUE cuz we could potentially fetch data using this key, we also want the right encoding to support non-english usernames? utf8_general_ci?. Then the password, we want to store the encrypted 256 character version of the password on the database, it doesnt need to be unique as two people may have the same password (weird lol) ...and finally, biography. we want that to be a large text, with maybe a limit of a thousand characters? and the right encoding, because again non-english characters might be posted up there.

      Now that we have made these notes, see how easy it is to create the right schema? We would not use a varchar(50) for the username column because we know we dont need that, we just need a varchar(15). You can use your imagination to see how this helps keep your application smart, and avoid some potential exploits you may have missed while programming.
      Last edited by CreativityKills; 15.07.12, 09:58.


        That naughty CSRF exploit

        If this is your first time hearing of CSRF then where have you been? Anyway I think if you haven't come across this then you haven't come across a notorious hack that at least 60% of web sites that accept input are susceptible to. Basically what CSRF is simply put is: having someone do what you can't seem to do. For instance, I want to exploit a community and delete a certain user... but man that damn login box is immune to SQLi (sql injection) so i cannot log in... oh wait there's CSRF, i can trick the admin into doing it for me WITHOUT HIM EVEN KNOWING! << That my friends is what CSRF can do. Someone with permission (usually with a role like admin) helps the hacker do the dirty work.

        Okay I'm done with the introduction, lets see how it works. By default, your browser when requesting a web page, loads every component separately. Meaning it loads the page, sends a HTTP request (with cookies, sessions of course) to the web server and requests other components like images, css, js, etcetera. Now the key point here is that it sends cookies and session data.

        To explain follow this block of code with your imagination:

        PHP Code:
         * An admin delete user page of a community.
        // Start session

        // Check if is logged in as admin
        if ( ! isset($_SESSION['admin_id']))
        'You are not an admin.');

        // Retrieve user id to delete
        $user_id = isset($_GET['id']) ? (int) $_GET['id'] : 0;

        // prepare SQL that deletes
        $sql strtr("DELETE FROM `users_table` WHERE `id`=':id'", array(':id' => mysql_real_escape_string($user_id)));

        // Run that prepared SQL
        $result mysql_query($sql);

        // Deletion status
        $user_deleted = (bool) $result;

        // Print result from query
        echo $user_deleted 'User deleted successfully.' 'Failed to delete user.'
        Now thats the underlying code to a pretty strong php script that is really rock-solid against SQLi. So you can rest assured that no SQLi is going through that baby. But how can this page be exploited by CSRF? One line of code is enough:
        <img src="" alt="Image Deleted." />
        Yes, i know, simple right? Now all that is left is to get the logged in admin to view a HTML page with this code. Later i can show you how XSS + CSRF can be a friggin deadly combination (using your imagination I'm sure you can probably already guess). Anyway, lemme explain a bit how that hack works.

        Remember i said that every page component is loaded separately? well, i omitted something: every page component, even images, are loaded (like a GET request) with the cookies, sessions etc attached to the HTTP request. So when somehow a logged in admin requests a page with such coding, regardless of whether its a valid image or not, the request is made.

        Lets now see how everything flows with the HTTP request while viewing that page...
        1. Admin logs into his site normally, thus saving a VALID session cookie on his browser
        2. Admin is still logged in and somehow navigates to the page with the above exploit
        3. Browser sends a request to load the HTML page and also a request to load the file in the img src
        4. Browser: Okay im supposed to load ummm lemme see oh yeah:
        5. Browser: Okay, sending a request to the server hosting the file...oh wait i almost forgot, heres the cookies i have hope you like them
        6. Admin server: Hey i recieved a request for one of my pages, and hey it contains nice cookies as a token ...aww how nice, and its just exactly how i like it. Accepted. Sending back response
        7. Apache: Validates cookies, sends back HTML content and HTTP response to the browser
        8. Browser: Hey nice reply, so lemme see what ive got..HTML? what the... i requested a friggin image man
        9. Browser: its not an image but hey im not the one who requested a php page, serving text in alt attribute

        As you can see, the request is made just like a GET request, the difference is that the Admin has no clue what so ever. And thus the user with the id is deleted and the hacker just wrote one line of code. Now, im guilty of using this method when deleting some annoying members during my time as a lava enthusiast LOL, especially when people thought they were free from the menace of HTTP sniffing using server access logs. Some people here are all too familiar with the switch in lava scripts from $session = $_GET['sess'] to $session = $_SESSION['id']; ... Aaaanyway, lets not deviate.

        Problem is simple, the solution? Not hard either. We have to do some sort of mechanism to block the code from executing, server side. Now again simple coding practices can cut this type of hack by half. What practice is this? Using only $_POST request method to execute deletes, updates. Thus adding something like a form with 'Are you sure you want to delete this is?' and a hidden value with id can fix this to a certain level, but NOT 100% ...not even 50%. but at least its a starting point. Now lets see how we can effectively change that code thats vulnerable to a solid state.

        PHP Code:
         * Admin delete page.
         * Deletes a user from the database.

        // Start session

        // Is admin logged in?
        $admin_logged_in = isset($_SESSION['admin_id']) ? $_SESSION['admin_id'] : FALSE;

        if (
        $admin_logged_in === FALSE)
        // Admin is NOT logged in, exit
        die('Restricted access.');

        // Get ID from initial request for deleting
        $delete_id = isset($_GET['id']) ? (int) $_GET['id'] : FALSE;

        // Was a form posted?
        if ($_POST)
        // Get the posted form token
        $form_token = isset($_POST['token']) ? $_POST['token'] : NULL;
        $session_token = isset($_SESSION['sess_token']) ? $_SESSION['sess_token'] : NULL;

        // Only proceed if session token and posted token are a match!
        if ( ! empty($form_token) AND ! empty($session_token) AND ($form_token === $session_token))
        // Get the id
        $delete_id = isset($_POST['id']) ? (int) $_POST['id'] : 0;

        // prepare SQL that deletes 
        $sql strtr("DELETE FROM `users_table`
                        WHERE `id`=':id'"
        ':id' => mysql_real_escape_string($delete_id)

        // Run that prepared SQL 
        $result mysql_query($sql); 

        // Delete the session token to avoid reuse

        // Confirmation
        exit('User has been deleted.');

        // Generate and save a random form token
        $sess_token $_SESSION['sess_token'] = md5(uniqid(rand(),TRUE));

        <!-- confirmation_form -->
         <form name="confirm" action="" method="POST">
          <input type="hidden" name="token" value="<?php echo $session_token ?>" />
          <input type="hidden" name="id" value="<?php echo $delete_id ?>" />
          Are you sure you want to delete this user?<br />
          <input name="submit" type="submit" value="Yes" /> <a href="admincp.php">No</a>
        <!-- / confirmation_form -->
        In case you did not notice the modifications, we have added a confirmation message so that everytime you want to delete a user you have to manually submit a form. A form that contains a randomly generated string that needs to match the one created in the script at loading time. This complicates things a little for the CSRF exploit. And honestly it solves 95% of the problem, the other 5% is reserved for reeeeaaallly smart guys, im talking of the Zuckerberg's and the Lerdorf's of this world. So you see again, coding practices can help alot, dont be a lazy developer, if you are, YOU WILL GET HACKED.
        Last edited by CreativityKills; 15.07.12, 14:31.


          Ability to put files on your server

          XSS is usually a browser based hack. It involves injecting, but this time injecting HTML to a page. The hacker injects HTML to your existing HTML page, thereby having complete control of your HTML content. including adding javascript. The hacker could, put an endless loop of alert boxes, redirect your traffic, force you to click something, force you to like some facebook page, deface your website, you name it! Oh and yeah he can carry out a more effective CSRF hack. Now im sure no one wants that. So there's one lagging question. How in Gods name can a hacker manipulate my HTML content without access to my server?

          Well heres the answer, database content. You see in sites that allow posting, like forums, comment boxes and the likes, a user can submit any data s/he wishes (including HTML). It has no effect on you mysql database, but what happens when the data is being retrieved and displayed? Yeah, fully functional HTML code... if not handled properly.

          So the next question, how do I handle this properly. One simple answer: the htmlspecialchars() function in PHP. This function escapes all strings passed to it and filters out the HTML content so its displayed in your browser as text not executable HTML.

          What im saying is this, right now i am posting a message to this awesome coding-talk forum yeah? If i was to post <b>bold</b> and submit, it goes to the database, and you are reading that now right? <b>bold</b>, <b>BOLD</b> <b>booooooold</b> why am i not executing as html? SIMPLE BECAUSE the data i submitted to the database as HTML is being escaped on display by the vBulletin engine. If it were another less secure engine the text might have actually been bold.

          So how to use htmlspecialchars?
          Unfortunately, I have seen some developers here use this function before inputting data into database. This is wrong and should be avoided. The function should be used only when retrieving data from the database. Off the top i can think of a reason why you shouldnt escape using htmlspecialchars before inserting to database. Suppose we have a `forum_posts` table and a `forum_text` column that accepts each users post. Now lets say we planned the schema to accept just 6 characters like varchar(6) ... imaging someone were posting to that forum and he submitted: i <3 u ... now thats a valid six character string yeah? Okay. Now if the programmer escapes the data with htmlspecialchars() before inputting the data we'll have this...

          PHP Code:
          // Data posted was 'i <3 u'
          $data 'i <3 u';

          // escape using htmlspecialchars (WRONG)
          $data htmlspecialchars(mysql_real_escape_string($data));

          // Insert into db
          mysql_query("INSERT INTO `some_table` (`forum_posts`) VALUES('".$data."'"); 
          After running that, check your database, you will have something like: i &gt; ...thats not what the user submitted is it? Alright now lets try the without

          PHP Code:
          // Data posted was 'i <3 u'
          $data 'i <3 u';

          // escape without using htmlspecialchars
          $data mysql_real_escape_string($data);

          // Insert into db
          mysql_query("INSERT INTO `some_table` (`forum_posts`) VALUES('".$data."'"); 
          Now that brings up: i <3 u in the database. But remember though that the htmlspecialchars MUST be used to retrieve data from the database, especially if the data we are retrieving is a string. So we want to display a users $post, instead of doing <?php echo $post ?> we'll do <?php echo htmlspecialchars($post) ?>

          Now what of thoose that want the user posting messages to have some sort of HTML capabilities to style their post? Using htmlspecialchars wont be appropriate in this scenario, but there are third-party scripts that fiilter out bad html tags and leaves the rest like HTMLPurifier. Though they usually have loading time impacts and should be used as little as possible.

          Added after 20 minutes:

          File uploads is an integral part of app development especially for communities. You may want users to upload photos to ur site. while thats cool and all, there are alot of dangers. First you cant always exppect a user to upload a picture., song, video, or .pdf etc. A user can upload an executable script.

          Now theres a lot of misconception out there that once you block .php file uploads you are safe. i always LOL and ROFL anytime i see such coding. But we php develoeprs always forget there are other scription languages, and their files are usually executable on web hostiing servers. for instance a .bs, .cgi, .ror files are all executable and can do some amount of damage.

          Im not going to go into how you can protect yourself. Im going to however give you pointers so you can develop, thats how i learnt, thats the best way to learn.

          First thing to consider when allowing uploads is the array of allowed file types. Is it a picture upload? then .gif, .png, .bmp, .tiff etc are valid picture formats so we only want php to allow that. Then its always a good practice to randomize the name of the file being uploaded (i take this cue from looking at the files on my jailbroken iphone, some files are labeled 974849-9848640-982798724GDSH-OIYRJ lol i dont know what they do, but the iphone does. So code in such a way that your script can find the file whenever it wants, but even you cant do it manually. Next thing is, try to save the uploads outside your root directory. If its a picture or a downloadable content however this may be impractical. And last but not the least, use your .htaccess file wisely (apache users). You can place .htaccess files in the uploads directory and deny access to files that dont have the valid extensions for that upload folder. Meaning that even if a php document finds its way in there, it cannot be executed because probably the .htaccess says any file thats not .gif, .png, .gif etc cannot be accessed. Also, make sure you disable script execution in that folder using .htaccess, this is another onion layer of security to consider.

          So those are my tips, use google wisely to find snippets and work with the tips above. Mix and Match... you cant go wrong.
          Last edited by CreativityKills; 15.07.12, 15:16.


            Use a Framework!

            Now we are starting a new PHP projects and theres a lot to consider. The scope, database schema, the environments, the script architechture etc. There are a whooooooooooooooooole lot of things to consider. While its more satisfying to create scripts from ground up, its less logical, especially if its a large project. I will give you one piece of advice. Use a PHP framework.

            A PHP Framework is simply a set of classes that packages all the mostly used PHP functions and helps you develop faster. Now you may not see the need to use a PHP framework at this point but let me tell you why i use a framework when developing.
            1. Time. PHP frameworks bundle most functions you otherwise would have to code from scratch. This helps develop faster
            2. Architechture. Most PHP frameworks are built with very commendable architechture that makes it easier to find files, bugs, and distribute open source for other developers to hack, create extensions and improve.
            3. Database Access. Most Frameworks have database classes that support multiple database engines and their classes are abstracted in such a way that you dont have to change much when (in a weird case) you are switching database engines. Also they have Active Records / ORM ...that helps optimize and improve the way you retrieve data from database. Not to mention some automatically escape the data thus safeguarding you from SQLi attacks.
            4. Uploads class. Some frameworks come with some sort of uploads class that helps you easily filter out nasty file extensions and manage your uploads eeeeasily.
            5. Modular design. Some frameworks come packed with HMVC that helps you build reusable "widgets" for your site. Example, build a "latest tweets" widget and call it anytime from anywhere in the application.

            There are many more reasons to use a framework but since this is a security related article im writing centered on that. You see that with a framework your site is already at least 70% safe. The rest is up to you to write good codes and use their coding standards (if they have one). Also participate in whatever community they have.

            Now there are cases where using a Framework may be an overkill. Like creating a simple web site, so i will advice using frameworks for larger projects.

            Now there are literally hundreds of PHP frameworks all having their selling points. Now the decision on which framework to use largely depends on you and your project. That said i can list the ones that have great reviews online, in no particular order.

            Kohana Framework. This has been my framework of choice and my starting point to 70% of my projects that require extensive coding.

            Zend Framework. This is considered to be the most complete framework in terms of classes and functions. Its also arguably the most widely used and trusted. Especially because its created by PHP themselves.

            CodeIgniter. The easiest framework to use so far. I would definately recommend using this as a starting point when you venture into the world of PHP frameworks and OOP. Their documentation is unarguably the BEST.

            Symfony. I have not really used this framework because I was already subscribed to Kohana and learning a new framework is not something i have time to do but i have heard is awesome and is worth mentioning.

            Yii Framework. Considered to be the best for web 2.0 development. I havent tried this also so i cannot really say much. But im guessing its popular for a reason.

            FuelPHP. This is from the makers of CodeIgniter. And in my opinion is a nice blend of Kohana and CodeIgniter. But im really not attracted to it for no reason in particular. BTW its PHP 5.3+

            Laravel. There has been A LOT of buzz recently about this framework that i had to try it on a new project i was starting a few days ago, and yes it was awesome! I mean its sooo easy building decoupled applications with this framework. Will definately recommend this, but not as a starting point for framework users.

            There are other amazing frameworks, some good, some not so good. But largely they are very good to use because it takes away the stress of setting up new projects. And most of all, the codes are unit tested and bugs are fixed regularly, thus helping you keep your site safe.
            Last edited by CreativityKills; 24.07.12, 05:21. Reason: Added a framework


              That's all. Questions are allowed


                Originally posted by CreativityKills View Post
                A form that contains a randomly generated string that needs to match the one created in the script at loading time.
                A randomly generated string on all important links (not just forms) is also a good idea because your users are at risk of this also not just admin
                Last edited by something else; 01.02.13, 21:09.


                  Good work ,
                  read the whole thing.
                  Mobile chat, iphone chat, android chat, chat, rooms


                    Thanks. Happy to help.