]> git.joonet.de Git - adminer.git/commitdiff
Protect CSRF token against BREACH
authorJakub Vrana <jakub@vrana.cz>
Fri, 25 Oct 2013 02:10:50 +0000 (19:10 -0700)
committerJakub Vrana <jakub@vrana.cz>
Fri, 25 Oct 2013 02:10:50 +0000 (19:10 -0700)
adminer/include/auth.inc.php
adminer/include/bootstrap.inc.php
adminer/include/functions.inc.php
adminer/include/lang.inc.php
adminer/sql.inc.php
changes.txt

index c53e1ca70b4c95d2a1e527f656f8fc5fbfcb207c..b64b3ac2931f00f93e3dd31a434c68aea4678471 100644 (file)
@@ -1,10 +1,11 @@
 <?php
 $connection = '';
 
-$token = $_SESSION["token"];
-if (!$_SESSION["token"]) {
+$has_token = $_SESSION["token"];
+if (!$has_token) {
        $_SESSION["token"] = rand(1, 1e6); // defense against cross-site request forgery
 }
+$token = get_token(); ///< @var string CSRF protection
 
 $permanent = array();
 if ($_COOKIE["adminer_permanent"]) {
@@ -40,7 +41,7 @@ if ($auth) {
        }
        
 } elseif ($_POST["logout"]) {
-       if ($token && $_POST["token"] != $token) {
+       if ($has_token && !verify_token()) {
                page_header(lang('Logout'), lang('Invalid CSRF token. Send the form again.'));
                page_footer("db");
                exit;
@@ -75,13 +76,13 @@ function unset_permanent() {
 }
 
 function auth_error($exception = null) {
-       global $connection, $adminer, $token;
+       global $connection, $adminer, $has_token;
        $session_name = session_name();
        $error = "";
        if (!$_COOKIE[$session_name] && $_GET[$session_name] && ini_bool("session.use_only_cookies")) {
                $error = lang('Session support must be enabled.');
        } elseif (isset($_GET["username"])) {
-               if (($_COOKIE[$session_name] || $_GET[$session_name]) && !$token) {
+               if (($_COOKIE[$session_name] || $_GET[$session_name]) && !$has_token) {
                        $error = lang('Session expired, please login again.');
                } else {
                        $password = get_password();
@@ -143,14 +144,13 @@ if (is_string($connection) || !$adminer->login($_GET["username"], get_password()
 
 $driver = new Min_Driver($connection);
 
-$token = $_SESSION["token"]; ///< @var string CSRF protection
 if ($auth && $_POST["token"]) {
        $_POST["token"] = $token; // reset token after explicit login
 }
 
 $error = ''; ///< @var string
 if ($_POST) {
-       if ($_POST["token"] != $token) {
+       if (!verify_token()) {
                $ini = "max_input_vars";
                $max_vars = ini_get($ini);
                if (extension_loaded("suhosin")) {
index 3a1bc35e48d974764aa619b7f538d5fcb581b04e..eaaab5a711fd595396cd17b2979948de08aa6a0a 100644 (file)
@@ -25,7 +25,7 @@ if (isset($_GET["file"])) {
 
 include "../adminer/include/functions.inc.php";
 
-global $adminer, $connection, $drivers, $edit_functions, $enum_length, $error, $functions, $grouping, $HTTPS, $inout, $jush, $LANG, $langs, $on_actions, $permanent, $structured_types, $token, $translations, $types, $unsigned, $VERSION; // allows including Adminer inside a function
+global $adminer, $connection, $drivers, $edit_functions, $enum_length, $error, $functions, $grouping, $HTTPS, $inout, $jush, $LANG, $langs, $on_actions, $permanent, $structured_types, $has_token, $token, $translations, $types, $unsigned, $VERSION; // allows including Adminer inside a function
 
 if (!$_SERVER["REQUEST_URI"]) { // IIS 5 compatibility
        $_SERVER["REQUEST_URI"] = $_SERVER["ORIG_PATH_INFO"];
index 08e42dae1a69461c9ed653a7570669d4950db443..6d1cd28736dff6b32762d8802645f725c0994f0e 100644 (file)
@@ -1124,6 +1124,22 @@ var timeout = setTimeout(function () {
        return array_keys($return);
 }
 
+/** Generate BREACH resistant CSRF token
+* @return string
+*/
+function get_token() {
+       $rand = rand(1, 1e6);
+       return ($rand ^ $_SESSION["token"]) . ":$rand";
+}
+
+/** Verify if supplied CSRF token is valid
+* @return bool
+*/
+function verify_token() {
+       list($token, $rand) = explode(":", $_POST["token"]);
+       return ($rand ^ $_SESSION["token"]) == $token;
+}
+
 // used in compiled version
 function lzw_decompress($binary) {
        // convert binary string to codes
index 86f1244b2b769418f69ac013f1608f7276dda610..bf430d188fd60dbdaf883c1c0919f7c732ea3851 100644 (file)
@@ -76,11 +76,11 @@ function switch_lang() {
        echo "<form action='' method='post'>\n<div id='lang'>";
        echo lang('Language') . ": " . html_select("lang", $langs, $LANG, "this.form.submit();");
        echo " <input type='submit' value='" . lang('Use') . "' class='hidden'>\n";
-       echo "<input type='hidden' name='token' value='$_SESSION[token]'>\n"; // $token may be empty in auth.inc.php
+       echo "<input type='hidden' name='token' value='" . get_token() . "'>\n"; // $token may be empty in auth.inc.php
        echo "</div>\n</form>\n";
 }
 
-if (isset($_POST["lang"]) && $_SESSION["token"] == $_POST["token"]) { // $token and $error not yet available
+if (isset($_POST["lang"]) && verify_token()) { // $error not yet available
        cookie("adminer_lang", $_POST["lang"]);
        $_SESSION["lang"] = $_POST["lang"]; // cookies may be disabled
        $_SESSION["translations"] = array(); // used in compiled version
index 72afbea75d134520718aa7cc03dc13f0382b753d..eb4fa1c7bd98285b091c80ebd88bab166cd3fd30 100644 (file)
@@ -218,6 +218,7 @@ if (!isset($_GET["import"])) {
 
 echo checkbox("error_stops", 1, ($_POST ? $_POST["error_stops"] : isset($_GET["import"])), lang('Stop on error')) . "\n";
 echo checkbox("only_errors", 1, $_POST["only_errors"], lang('Show only errors')) . "\n";
+echo "<input type='hidden' name='token' value='$token'>\n";
 
 if (!isset($_GET["import"]) && $history) {
        print_fieldset("history", lang('History'), $_GET["history"] != "");
@@ -231,5 +232,4 @@ if (!isset($_GET["import"]) && $history) {
        echo "</div></fieldset>\n";
 }
 ?>
-<input type="hidden" name="token" value="<?php echo $token; ?>">
 </form>
index b891168d7542cfd2891450c4604568c4c1b4a1cd..277ea3b90893df1bd3007a090bde33959f401260 100644 (file)
@@ -15,6 +15,7 @@ Encrypt passwords stored in session by a key stored in cookie
 Don't append newlines to uploaded files, bug since Adminer 3.7.0
 Don't display SQL edit form on Ctrl+click on the select query, introduced in Adminer 3.6.4
 Use MD5 for editing long keys only in supported drivers, bug since Adminer 3.6.4
+Protect CSRF token against BREACH
 SQLite: Allow editing primary key
 SQLite: Allow editing foreign keys
 PostgreSQL: Fix handling of nextval() default values