Bonfire icon indicating copy to clipboard operation
Bonfire copied to clipboard

Codeigniter cookies too strict

Open boblennes opened this issue 9 years ago • 4 comments

I had an issue last night with one of my Bonfire apps running alongside an ecommerce app. Apparently cookie names can have additional characters now like period, ']', '[', '%' and '@' The problem cookie for me was from Adobe (thanks Adobe! ha..). The symptom is the page wont render, only there is a message "Disallowed key characters".

So the fix is in the input helper but I wasn't sure where it belonged in Bonfire. Here's the code:

<?php

class MY_Input extends CI_Input {

    /**
     * Clean Keys
     *
     * This is a helper function. To prevent malicious users
     * from trying to exploit keys we make sure that keys are
     * only named with alpha-numeric text and a few other items.
     * 
     * Extended to allow: 
     *      '.' (dot), '[' (open bracket), ']' (close bracket), '@' ("at"), '%' (percent)
     * 
     * @access  private
     * @param   string
     * @return  string
     */
    function _clean_input_keys($str) {
        if (!preg_match("/^[A-Za-z0-9:_\/-\[\]@%\.]+$/i", $str)) {
            /**
             * Check for Development environment - Non-descriptive 
             * error so show me the string that caused the problem 
             */
            if (getenv('ENVIRONMENT') && getenv('ENVIRONMENT') == 'DEVELOPMENT')
                var_dump($str);
            exit('Disallowed Key Characters.');
        }

        // Clean UTF-8 if supported
        if (UTF8_ENABLED === TRUE) {
            $str = $this->uni->clean_string($str);
        }

        return $str;
    }

}

boblennes avatar Sep 17 '14 17:09 boblennes

Unfortunately, the function is used for the $_GET and $_POST arrays, too, so it would probably be better to override _sanitize_globals() and pass off the cleaning of the cookie's keys to a different method.

Another option would be to add a check to sanitize_globals() for something which would identify the failing cookie properly and skip the call to clean the key/data for that particular cookie (since there's already logic in place to do this for the session cookie if it is encrypted, this may be the easiest, and safest, option).

mwhitneysdsu avatar Sep 17 '14 20:09 mwhitneysdsu

I looked at the latest Codeigniter dev and it may be addressed by ignoring bad keys rather than dying:

        // Clean $_COOKIE Data
        if (is_array($_COOKIE) && count($_COOKIE) > 0)
        {
            // Also get rid of specially treated cookies that might be set by a server
            // or silly application, that are of no use to a CI application anyway
            // but that when present will trip our 'Disallowed Key Characters' alarm
            // http://www.ietf.org/rfc/rfc2109.txt
            // note that the key names below are single quoted strings, and are not PHP variables
            unset(
                $_COOKIE['$Version'],
                $_COOKIE['$Path'],
                $_COOKIE['$Domain']
            );

            foreach ($_COOKIE as $key => $val)
            {
                if (($cookie_key = $this->_clean_input_keys($key)) !== FALSE)
                {
                    $_COOKIE[$cookie_key] = $this->_clean_input_data($val);
                }
                else
                {
                    unset($_COOKIE[$key]);
                }
            }
        }

and

    /**
     * Clean Keys
     *
     * Internal method that helps to prevent malicious users
     * from trying to exploit keys we make sure that keys are
     * only named with alpha-numeric text and a few other items.
     *
     * @param   string  $str    Input string
     * @param   string  $fatal  Whether to terminate script exection
     *              or to return FALSE if an invalid
     *              key is encountered
     * @return  string|bool
     */
    protected function _clean_input_keys($str, $fatal = TRUE)
    {
        if ( ! preg_match('/^[a-z0-9:_\/|-]+$/i', $str))
        {
            if ($fatal === TRUE)
            {
                return FALSE;
            }
            else
            {
                set_status_header(503);
                echo 'Disallowed Key Characters.';
                exit(7); // EXIT_USER_INPUT
            }
        }

        // Clean UTF-8 if supported
        if (UTF8_ENABLED === TRUE)
        {
            return $this->uni->clean_string($str);
        }

        return $str;
    }

boblennes avatar Sep 20 '14 01:09 boblennes

You could try something like the following, but I haven't tested to determine whether anything else would need to be updated to use the CI 3 methods correctly/safely.

https://gist.github.com/mwhitneysdsu/19c7bd5fb1f9192e93f7#file-bf_input-php

This file could be placed in /bonfire/core/ to replace the methods defined in /bonfire/codeigniter/core/Input.php.

Note that I had to change the visibility of the methods and change one function call to make it compatible with CI2.x, but this still doesn't guarantee that everything is functioning as it should. For instance, much of the Security code has changed significantly in CI3, so the Input class may be assuming that the Security class will be more aggressive in some areas.

mwhitneysdsu avatar Sep 22 '14 14:09 mwhitneysdsu

This seems to be working quite well.

boblennes avatar Oct 21 '14 02:10 boblennes