]> source.dussan.org Git - nextcloud-server.git/commitdiff
Backport CSRF prevention.
authorThomas Tanghus <thomas@tanghus.net>
Thu, 14 Jun 2012 11:52:22 +0000 (13:52 +0200)
committerThomas Tanghus <thomas@tanghus.net>
Thu, 14 Jun 2012 11:52:22 +0000 (13:52 +0200)
core/templates/layout.user.php
lib/json.php
lib/public/json.php
lib/public/util.php
lib/template.php
lib/util.php

index e9d105ed04329934d5dcfcb9c032a46d1431a0c8..f9d879813590532865a994889bbb17b5896fc2ed 100644 (file)
                                echo '/>';
                        ?>
                <?php endforeach; ?>
+               <script type="text/javascript">
+                       $(function() {
+                               var requesttoken = '<?php echo $_['requesttoken']; ?>';
+                               $(document).bind('ajaxSend', function(elm, xhr, s){
+                                       if(requesttoken) {
+                                               xhr.setRequestHeader('requesttoken', requesttoken);
+                                       }
+                               });
+                       });
+               </script>
        </head>
 
        <body id="<?php echo $_['bodyid'];?>">
index f3bbe9ac89976767adf01441d329970fc0457631..dfc0a7b894e199187a3d9487c44094b6a431c302 100644 (file)
@@ -41,6 +41,18 @@ class OC_JSON{
                }
        }
 
+       /**
+        * @brief Check an ajax get/post call if the request token is valid.
+        * @return json Error msg if not valid.
+        */
+       public static function callCheck(){
+               if( !OC_Util::isCallRegistered()){
+                       $l = OC_L10N::get('core');
+                       self::error(array( 'data' => array( 'message' => $l->t('Token expired. Please reload page.') )));
+                       exit();
+               }
+       }
+        
        /**
        * Check if the user is a admin, send json error msg if not
        */
index 439721ac6cec3151dc2a52645bda6e4d9a6b996f..69a699254576c35b1ce60040a1107d6ce62c899e 100644 (file)
@@ -53,6 +53,13 @@ class JSON {
                return(\OC_JSON::checkLoggedIn());
        }
 
+       /**
+        * @brief Check an ajax get/post call if the request token is valid.
+        * @return json Error msg if not valid.
+        */
+       public static function callCheck(){
+               return(\OC_JSON::callCheck());
+       }
 
        /**
        * @brief Send json success msg
index 2abffba4c4a92983ea168c402cc3666127416d6e..bffe07da3f8b732c707623c16af4536be6a65dfe 100644 (file)
@@ -249,6 +249,22 @@ class Util {
                return(\OC_Hook::emit( $signalclass, $signalname, $params ));
        }
 
+       /**
+        * Register an get/post call. This is important to prevent CSRF attacks
+        * TODO: write example
+        */
+       public static function callRegister(){
+               return(\OC_Util::callRegister());
+       }
+
+
+       /**
+        * Check an ajax get/post call if the request token is valid. exit if not.
+        * Todo: Write howto
+        */
+       public static function callCheck(){
+               return(\OC_Util::callCheck());
+       }
 
 }
 
index e908c76bfadf0c2ba76af716b5d2bf0f78e3b911..fd2cb34a4a922d71862bef1d0d824e801ef6a70b 100644 (file)
@@ -155,11 +155,13 @@ class OC_Template{
                $this->renderas = $renderas;
                $this->application = $app;
                $this->vars = array();
+               if($renderas == 'user') {
+                       $this->vars['requesttoken'] = OC_Util::callRegister();
+               }
                $this->l10n = OC_L10N::get($app);
-                header('X-Frame-Options: Sameorigin');
-                header('X-XSS-Protection: 1; mode=block');
-                header('X-Content-Type-Options: nosniff');
+               header('X-Frame-Options: Sameorigin');
+               header('X-XSS-Protection: 1; mode=block');
+               header('X-Content-Type-Options: nosniff');
                $this->findTemplate($name);
        }
 
@@ -355,6 +357,7 @@ class OC_Template{
                        if( $this->renderas == "user" ){
                                $page = new OC_Template( "core", "layout.user" );
                                $page->assign('searchurl',OC_Helper::linkTo( 'search', 'index.php' ));
+                               $page->assign('requesttoken', $this->vars['requesttoken']);
                                if(array_search(OC_APP::getCurrentApp(),array('settings','admin','help'))!==false){
                                        $page->assign('bodyid','body-settings');
                                }else{
index 49f658f3c0e908d3a335683738f5d6ff244a2d91..c47a7e5d84c242dff82c85dbaf85352f2ac4f797 100644 (file)
@@ -331,4 +331,77 @@ class OC_Util {
                }
                exit();
        }
+
+       /**
+        * @brief Register an get/post call. This is important to prevent CSRF attacks
+        * Todo: Write howto
+        * @return $token Generated token.
+        */
+       public static function callRegister(){
+               //mamimum time before token exires
+               $maxtime=(60*60);  // 1 hour
+
+               // generate a random token.
+               $token=mt_rand(1000,9000).mt_rand(1000,9000).mt_rand(1000,9000);
+
+               // store the token together with a timestamp in the session.
+               $_SESSION['requesttoken-'.$token]=time();
+
+               // cleanup old tokens garbage collector
+               // only run every 20th time so we donĀ“t waste cpu cycles
+               if(rand(0,20)==0) {  
+                       foreach($_SESSION as $key=>$value) {
+                               // search all tokens in the session
+                               if(substr($key,0,12)=='requesttoken') {
+                                       if($value+$maxtime<time()){
+                                               // remove outdated tokens
+                                               unset($_SESSION[$key]);                                         
+                                       }
+                               }       
+                       }
+               }
+               // return the token
+               return($token);
+       }
+
+       /**
+        * @brief Check an ajax get/post call if the request token is valid.
+        * @return boolean False if request token is not set or is invalid.
+        */
+       public static function isCallRegistered(){
+               //mamimum time before token exires
+               $maxtime=(60*60);  // 1 hour
+               if(isset($_GET['requesttoken'])) {
+                       $token=$_GET['requesttoken'];
+               }elseif(isset($_POST['requesttoken'])){
+                       $token=$_POST['requesttoken'];
+               }elseif(isset($_SERVER['HTTP_REQUESTTOKEN'])){
+                       $token=$_SERVER['HTTP_REQUESTTOKEN'];
+               }else{
+                       //no token found.
+                       return false;
+               }
+               if(isset($_SESSION['requesttoken-'.$token])) {
+                       $timestamp=$_SESSION['requesttoken-'.$token];
+                       if($timestamp+$maxtime<time()){
+                               return false;
+                       }else{
+                               //token valid
+                               return true;
+                       }
+               }else{
+                       return false;
+               }
+       }
+
+       /**
+        * @brief Check an ajax get/post call if the request token is valid. exit if not.
+        * Todo: Write howto
+        */
+       public static function callCheck(){
+               if(!OC_Util::isCallRegistered()) {
+                       exit;
+               }
+       }
 }
+