Aleksander Machniak
2015-09-08 26086981a24e72f283da38dbdb992f27b4135a80
Improve randomness of security tokens (#1490529)
5 files modified
69 ■■■■ changed files
.htaccess 2 ●●● patch | view | raw | blame | history
CHANGELOG 1 ●●●● patch | view | raw | blame | history
program/include/rcmail.php 2 ●●● patch | view | raw | blame | history
program/lib/Roundcube/rcube_utils.php 62 ●●●●● patch | view | raw | blame | history
tests/Framework/Utils.php 2 ●●● patch | view | raw | blame | history
.htaccess
@@ -32,7 +32,7 @@
# security rules:
# - deny access to files not containing a dot or starting with a dot
#   in all locations except installer directory
RewriteRule ^(?!installer|[a-f0-9]{16})(\.?[^\.]+)$ - [F]
RewriteRule ^(?!installer|[a-zA-Z0-9]{16})(\.?[^\.]+)$ - [F]
# - deny access to some locations
RewriteRule ^/?(\.git|\.tx|SQL|bin|config|logs|temp|tests|program\/(include|lib|localization|steps)) - [F]
# - deny access to some documentation files
CHANGELOG
@@ -1,6 +1,7 @@
CHANGELOG Roundcube Webmail
===========================
- Security: Improve randomness of security tokens (#1490529)
- Security: Use random security tokens instead of hashes based on encryption key (#1490404)
- Security: Improved encrypt/decrypt methods with option to choose the cipher_method (#1489719)
- Make optional adding of standard signature separator - sig_separator (#1487768)
program/include/rcmail.php
@@ -810,7 +810,7 @@
            // remove old token from the path
            $base_path = rtrim($base_path, '/');
            $base_path = preg_replace('/\/[a-f0-9]{' . strlen($token) . '}$/', '', $base_path);
            $base_path = preg_replace('/\/[a-zA-Z0-9]{' . strlen($token) . '}$/', '', $base_path);
            // this need to be full url to make redirects work
            $absolute = true;
program/lib/Roundcube/rcube_utils.php
@@ -1090,25 +1090,31 @@
    }
    /**
     * Generate a ramdom string
     * Generate a random string
     *
     * @param int  $length String length
     * @param bool $raw    Return RAW data instead of hex
     * @param bool $raw    Return RAW data instead of ascii
     *
     * @return string The generated random string
     */
    public static function random_bytes($length, $raw = false)
    {
        $rlen   = $raw ? $length : ceil($length / 2);
        $random = openssl_random_pseudo_bytes($rlen);
        // Use PHP7 true random generator
        if (function_exists('random_bytes')) {
            $random = @random_bytes($length);
        }
        if (!$random) {
            $random = openssl_random_pseudo_bytes($length);
        }
        if ($raw) {
            return $random;
        }
        $random = bin2hex($random);
        $random = self::bin2ascii($random);
        // if the length wasn't even...
        // truncate to the specified size...
        if ($length < strlen($random)) {
            $random = substr($random, 0, $length);
        }
@@ -1117,6 +1123,50 @@
    }
    /**
     * Convert binary data into readable form (containing a-zA-Z0-9 characters)
     *
     * @param string $input Binary input
     *
     * @return string Readable output
     */
    public static function bin2ascii($input)
    {
        // Above method returns "hexits".
        // Based on bin_to_readable() function in ext/session/session.c.
        // Note: removed ",-" characters from hextab
        $hextab = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        $nbits  = 6; // can be 4, 5 or 6
        $length = strlen($input);
        $result = '';
        $char   = 0;
        $i      = 0;
        $have   = 0;
        $mask   = (1 << $nbits) - 1;
        while (true) {
            if ($have < $nbits) {
                if ($i < $length) {
                    $char |= ord($input[$i++]) << $have;
                    $have += 8;
                }
                else if (!$have) {
                    break;
                }
                else {
                    $have = $nbits;
                }
            }
            // consume nbits
            $result .= $hextab[$char & $mask];
            $char  >>= $nbits;
            $have   -= $nbits;
        }
        return $result;
    }
    /**
     * Format current date according to specified format.
     * This method supports microseconds (u).
     *
tests/Framework/Utils.php
@@ -430,7 +430,7 @@
     */
    function test_random_bytes()
    {
        $this->assertSame(15, strlen(rcube_utils::random_bytes(15)));
        $this->assertRegexp('/^[a-zA-Z0-9]{15}$/', rcube_utils::random_bytes(15));
        $this->assertSame(15, strlen(rcube_utils::random_bytes(15, true)));
        $this->assertSame(1, strlen(rcube_utils::random_bytes(1)));
        $this->assertSame(0, strlen(rcube_utils::random_bytes(0)));