Johan Broddfelt
/* Comments on code */

Security is important

As the application is built now, we have a potential security issue. There is only taken care of SQL-injection on data that is saved to the database. But filter_input() does not prevent any malisious code to be posted into the system. So we want to replace that function with our own like this: Http::filter_input($method, $param, $filter). So that we can make a simple search and replace in our application and change all the instances to our secure one. Lets start by creating the file classes/Http.php

<?php
class Http {
    static function filter_input($method, $param, $filter=FILTER_DEFAULT) {
        // Since we know that almost all inputs are going to touch the database, 
        // we create a gate here were we prevent sql-injection amongst other things
        return String::slashText(filter_input($method, $param, $filter));
    }
}

Now we can do a search and replace in our entire codebase for filter_input and replace it with Http::filter_input. And from now on we always use the Http::filter_input to make sure that the input we send to our database is secured. In our index.php we will change the following code:

function printContent() {
    $module = filter_input(INPUT_GET, 'module', FILTER_SANITIZE_URL);
    $view = filter_input(INPUT_GET, 'view', FILTER_SANITIZE_URL);
    $id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT);

To this:

function printContent() {
    // stripcslashes is because Http::filter_input makes & and _ slashed. We do not want that on these values. They are not used in LIKE queries in the database
    $module = stripcslashes(Http::filter_input(INPUT_GET, 'module', FILTER_SANITIZE_URL));
    $view = stripcslashes(Http::filter_input(INPUT_GET, 'view', FILTER_SANITIZE_URL));
    $id = Http::filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT);

Notice that we use the stripcslashes() to remove the slashes from % and _ because we do not want them in our model and view variable. There is no security issue there. We also want to add stripcslashes() in places where post data is displayd in forms directly. Like in our search form in list. The only real reason for doing this is to avoid have the user think that the search query was changed, and that in some way made the search less effective.

    <form method="GET" action="">
        <input type="hidden" name="current_page" value="1">
        <input type="hidden" name="module" value="<?php echo $module; ?>">
        <input type="hidden" name="view" value="<?php echo $view; ?>">
        <input type="text" name="search_text" value="<?php echo stripcslashes($searchText); ?>">
        <input type="submit" class="button" name="search" value="Search">
    </form>

Now we are using % for wildcard search as default in this search form. But in some cases you might want to have the posibillity for the user to add a wildcard search instead. Then you use the *, as it is more wildly known to be a wildcard and in your query you replace all * with %. You might also do the same in order to get a single character wildcart and replace . with _ in the string.

I have previously discussed the String::slashText() function. But I add it her as well in order to remind you what it does. And I have also added some code to prevent any unexpected behavior if you for some reason would want to write #a# in your text. Preiously that would have resulted in an unexpected tag.

<?php
class String {
    static function slashText($text, $removeBlank=true) {
        // Remove all slashes for clean input
        $text = stripcslashes($text);

        // Clear all untrusted html-tags
        $text = String::stripDangerousHtml($text);

        // General cleanup of spaces, if demanded
        if ($removeBlank) {
            $text = preg_replace('/&nbsp;/', ' ', $text);
        }

        // Escape the string with the standard mysql function
        $text = Db::real_escape_string($text);

        return $text;
    }

    // Use this function to sequre LIKE statements in SQL
    // Ex: $qry = 'SELECT id FROM my_tbl WHERE name LIKE "' . String::likeSafe($name) . '"';
    // This is to avoid unwanted use of % or _ as wildcards if $name = 'b_d%';
    // If we do not use likeSafe then the query will find ALL posts with name like bad, bed, bedroom, body...
    function likeSafe($text) {
        return addcslashes(String::slashText($text), '%_');
    }
    
    static function stripDangerousHtml($text) {
        // Add faile safe
        $text = str_replace('###', '#-#-#', $text);
        $text = str_replace('¤¤¤', '¤-¤-¤', $text);
        
        // Remove all areas of code with potentially dangerous html/javascript code
        $text = preg_replace('/<script[^>]*?>.*?</script>/is', '', $text);
        $text = preg_replace('/<!--.*?-->/is', '', $text);
        
        // Secure all safe tags, only allowing tags and slashes. No other information inside tags.
        $text = preg_replace('/(<(/?)(b|p|i|u|s|span|li|lu|table|tr|th|td|cite|wbr|strong|em|italic|code|pre)(/?)>)/i', '###$2$3$4¤¤¤', $text);
        $text = preg_replace('/<(a).*?(href="[^"]*?").*?(target="[^"]*?")>/i', '###$1 $2 $3¤¤¤', $text);
        $text = preg_replace('/<(a).*?(href="[^"]*?")>/i', '###$1 $2¤¤¤', $text);
        $text = preg_replace('/(<(/a)>)/i', '###$2¤¤¤', $text);
        $text = preg_replace('/<(img)s+(src="[^"]*?")s+(style="[^"]*?")[^>]*?>/i', '###$1 $2 $3¤¤¤', $text);
        $text = preg_replace('/<(img)s+(src="[^"]*?")[^>]*?>/i', '###$1 $2¤¤¤', $text);
        $text = preg_replace('/<br.*?>/', '###br###', $text);

        // Remove all tags that are left
        $text = preg_replace('/<[^>]*?>/', '', $text);
        
        // Restore all safe tags
        $text = preg_replace('/###br###/', '<br>', $text);
        $text = preg_replace('/(###(/a)¤¤¤)/i', '<$2>', $text);
        $text = preg_replace('/(###(a.*?)¤¤¤)/i', '<$2>', $text);
        $text = preg_replace('/(###(img.*?)¤¤¤)/i', '<$2>', $text);
        $text = preg_replace('/(###(/?(b|p|i|u|s|span|li|lu|table|tr|th|td|cite|wbr|strong|em|italic|code|pre)/?)¤¤¤)/i', '<$2>', $text);

        // Restore the faile safe
        $text = str_replace('#-#-#', '###', $text);
        $text = str_replace('¤-¤-¤', '¤¤¤', $text);
        return $text;
    }

- Framework, PHP, Security

<< Delete post and Generic Class Authentication and users >>

Comment

Name
Mail (Not public)
Send mail uppdates on new comments

Comments

0 post found