зеркало из https://github.com/nextcloud/server.git
Merge pull request #178 from owncloud/JustOneCSRFTokenPerSession
Just one CSRF token per session
This commit is contained in:
Коммит
8c4c74b23f
|
@ -1,40 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
* @author Christian Reiner
|
||||
* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the license, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file core/ajax/requesttoken.php
|
||||
* @brief Ajax method to retrieve a fresh request protection token for ajax calls
|
||||
* @return json: success/error state indicator including a fresh request token
|
||||
* @author Christian Reiner
|
||||
*/
|
||||
|
||||
// don't load apps or filesystem for this task
|
||||
$RUNTIME_NOAPPS = true;
|
||||
$RUNTIME_NOSETUPFS = true;
|
||||
|
||||
// Sanity checks
|
||||
// using OCP\JSON::callCheck() below protects the token refreshing itself.
|
||||
//OCP\JSON::callCheck ( );
|
||||
OCP\JSON::checkLoggedIn ( );
|
||||
// hand out a fresh token
|
||||
OCP\JSON::success ( array ( 'token' => OCP\Util::callRegister() ) );
|
||||
?>
|
|
@ -40,7 +40,7 @@ OC.EventSource=function(src,data){
|
|||
dataStr+=name+'='+encodeURIComponent(data[name])+'&';
|
||||
}
|
||||
}
|
||||
dataStr+='requesttoken='+OC.Request.Token;
|
||||
dataStr+='requesttoken='+OC.EventSource.requesttoken;
|
||||
if(!this.useFallBack && typeof EventSource !='undefined'){
|
||||
this.source=new EventSource(src+'?'+dataStr);
|
||||
this.source.onmessage=function(e){
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @file core/js/requesttoken.js
|
||||
* @brief Routine to refresh the Request protection request token periodically
|
||||
* @author Christian Reiner (arkascha)
|
||||
* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the license, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
OC.Request = {
|
||||
// the request token
|
||||
Token: {},
|
||||
// the lifespan span (in secs)
|
||||
Lifespan: {},
|
||||
// method to refresh the local request token periodically
|
||||
Refresh: function(){
|
||||
// just a client side console log to preserve efficiency
|
||||
console.log("refreshing request token (lifebeat)");
|
||||
var dfd=new $.Deferred();
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: OC.filePath('core','ajax','requesttoken.php'),
|
||||
cache: false,
|
||||
data: { },
|
||||
dataType: 'json'
|
||||
}).done(function(response){
|
||||
// store refreshed token inside this class
|
||||
OC.Request.Token=response.token;
|
||||
dfd.resolve();
|
||||
}).fail(dfd.reject);
|
||||
return dfd;
|
||||
}
|
||||
}
|
||||
// accept requesttoken and lifespan into the OC namespace
|
||||
OC.Request.Token = oc_requesttoken;
|
||||
OC.Request.Lifespan = oc_requestlifespan;
|
||||
// refresh the request token periodically shortly before it becomes invalid on the server side
|
||||
setInterval(OC.Request.Refresh,Math.floor(1000*OC.Request.Lifespan*0.93)), // 93% of lifespan value, close to when the token expires
|
||||
// early bind token as additional ajax argument for every single request
|
||||
$(document).bind('ajaxSend', function(elm, xhr, s){xhr.setRequestHeader('requesttoken', OC.Request.Token);});
|
|
@ -13,9 +13,6 @@ $this->create('search_ajax_search', '/search/ajax/search.php')
|
|||
// AppConfig
|
||||
$this->create('core_ajax_appconfig', '/core/ajax/appconfig.php')
|
||||
->actionInclude('core/ajax/appconfig.php');
|
||||
// RequestToken
|
||||
$this->create('core_ajax_requesttoken', '/core/ajax/requesttoken.php')
|
||||
->actionInclude('core/ajax/requesttoken.php');
|
||||
// Share
|
||||
$this->create('core_ajax_share', '/core/ajax/share.php')
|
||||
->actionInclude('core/ajax/share.php');
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
var oc_webroot = '<?php echo OC::$WEBROOT; ?>';
|
||||
var oc_appswebroots = <?php echo $_['apps_paths'] ?>;
|
||||
var oc_requesttoken = '<?php echo $_['requesttoken']; ?>';
|
||||
var oc_requestlifespan = '<?php echo $_['requestlifespan']; ?>';
|
||||
</script>
|
||||
<?php foreach ($_['jsfiles'] as $jsfile): ?>
|
||||
<script type="text/javascript" src="<?php echo $jsfile; ?>"></script>
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
var oc_webroot = '<?php echo OC::$WEBROOT; ?>';
|
||||
var oc_appswebroots = <?php echo $_['apps_paths'] ?>;
|
||||
var oc_requesttoken = '<?php echo $_['requesttoken']; ?>';
|
||||
var oc_requestlifespan = '<?php echo $_['requestlifespan']; ?>';
|
||||
var datepickerFormatDate = <?php echo json_encode($l->l('jsdate', 'jsdate')) ?>;
|
||||
var dayNames = <?php echo json_encode(array((string)$l->t('Sunday'), (string)$l->t('Monday'), (string)$l->t('Tuesday'), (string)$l->t('Wednesday'), (string)$l->t('Thursday'), (string)$l->t('Friday'), (string)$l->t('Saturday'))) ?>;
|
||||
var monthNames = <?php echo json_encode(array((string)$l->t('January'), (string)$l->t('February'), (string)$l->t('March'), (string)$l->t('April'), (string)$l->t('May'), (string)$l->t('June'), (string)$l->t('July'), (string)$l->t('August'), (string)$l->t('September'), (string)$l->t('October'), (string)$l->t('November'), (string)$l->t('December'))) ?>;
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
var oc_appswebroots = <?php echo $_['apps_paths'] ?>;
|
||||
var oc_current_user = '<?php echo OC_User::getUser() ?>';
|
||||
var oc_requesttoken = '<?php echo $_['requesttoken']; ?>';
|
||||
var oc_requestlifespan = '<?php echo $_['requestlifespan']; ?>';
|
||||
var datepickerFormatDate = <?php echo json_encode($l->l('jsdate', 'jsdate')) ?>;
|
||||
var dayNames = <?php echo json_encode(array((string)$l->t('Sunday'), (string)$l->t('Monday'), (string)$l->t('Tuesday'), (string)$l->t('Wednesday'), (string)$l->t('Thursday'), (string)$l->t('Friday'), (string)$l->t('Saturday'))) ?>;
|
||||
var monthNames = <?php echo json_encode(array((string)$l->t('January'), (string)$l->t('February'), (string)$l->t('March'), (string)$l->t('April'), (string)$l->t('May'), (string)$l->t('June'), (string)$l->t('July'), (string)$l->t('August'), (string)$l->t('September'), (string)$l->t('October'), (string)$l->t('November'), (string)$l->t('December'))) ?>;
|
||||
|
@ -21,6 +20,13 @@
|
|||
<?php foreach($_['jsfiles'] as $jsfile): ?>
|
||||
<script type="text/javascript" src="<?php echo $jsfile; ?>"></script>
|
||||
<?php endforeach; ?>
|
||||
<script type="text/javascript">
|
||||
requesttoken = '<?php echo $_['requesttoken']; ?>';
|
||||
OC.EventSource.requesttoken=requesttoken;
|
||||
$(document).bind('ajaxSend', function(elm, xhr, s) {
|
||||
xhr.setRequestHeader('requesttoken', requesttoken);
|
||||
});
|
||||
</script>
|
||||
<?php foreach($_['headers'] as $header): ?>
|
||||
<?php
|
||||
echo '<'.$header['tag'].' ';
|
||||
|
|
|
@ -264,8 +264,6 @@ class OC{
|
|||
OC_Util::addScript( "jquery-tipsy" );
|
||||
OC_Util::addScript( "oc-dialogs" );
|
||||
OC_Util::addScript( "js" );
|
||||
// request protection token MUST be defined after the jquery library but before any $('document').ready()
|
||||
OC_Util::addScript( "requesttoken" );
|
||||
OC_Util::addScript( "eventsource" );
|
||||
OC_Util::addScript( "config" );
|
||||
//OC_Util::addScript( "multiselect" );
|
||||
|
|
|
@ -172,7 +172,6 @@ class OC_Template{
|
|||
$this->application = $app;
|
||||
$this->vars = array();
|
||||
$this->vars['requesttoken'] = OC_Util::callRegister();
|
||||
$this->vars['requestlifespan'] = OC_Util::$callLifespan;
|
||||
$parts = explode('/', $app); // fix translation when app is something like core/lostpassword
|
||||
$this->l10n = OC_L10N::get($parts[0]);
|
||||
|
||||
|
@ -391,7 +390,6 @@ class OC_Template{
|
|||
$page = new OC_TemplateLayout($this->renderas);
|
||||
if($this->renderas == 'user') {
|
||||
$page->assign('requesttoken', $this->vars['requesttoken']);
|
||||
$page->assign('requestlifespan', $this->vars['requestlifespan']);
|
||||
}
|
||||
|
||||
// Add custom headers
|
||||
|
|
29
lib/util.php
29
lib/util.php
|
@ -472,17 +472,6 @@ class OC_Util {
|
|||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Static lifespan (in seconds) when a request token expires.
|
||||
* @see OC_Util::callRegister()
|
||||
* @see OC_Util::isCallRegistered()
|
||||
* @description
|
||||
* Also required for the client side to compute the piont in time when to
|
||||
* request a fresh token. The client will do so when nearly 97% of the
|
||||
* timespan coded here has expired.
|
||||
*/
|
||||
public static $callLifespan = 3600; // 3600 secs = 1 hour
|
||||
|
||||
/**
|
||||
* @brief Register an get/post call. Important to prevent CSRF attacks.
|
||||
* @todo Write howto: CSRF protection guide
|
||||
|
@ -491,30 +480,24 @@ class OC_Util {
|
|||
* Creates a 'request token' (random) and stores it inside the session.
|
||||
* Ever subsequent (ajax) request must use such a valid token to succeed,
|
||||
* otherwise the request will be denied as a protection against CSRF.
|
||||
* The tokens expire after a fixed lifespan.
|
||||
* @see OC_Util::$callLifespan
|
||||
* @see OC_Util::isCallRegistered()
|
||||
*/
|
||||
public static function callRegister() {
|
||||
// Check if a token exists
|
||||
if(!isset($_SESSION['requesttoken']) || time() >$_SESSION['requesttoken']['time']) {
|
||||
if(!isset($_SESSION['requesttoken'])) {
|
||||
// No valid token found, generate a new one.
|
||||
$requestTokenArray = array(
|
||||
"requesttoken" => self::generate_random_bytes(20),
|
||||
"time" => time()+self::$callLifespan,
|
||||
);
|
||||
$_SESSION['requesttoken']=$requestTokenArray;
|
||||
$requestToken = self::generate_random_bytes(20);
|
||||
$_SESSION['requesttoken']=$requestToken;
|
||||
} else {
|
||||
// Valid token already exists, send it
|
||||
$requestTokenArray = $_SESSION['requesttoken'];
|
||||
$requestToken = $_SESSION['requesttoken'];
|
||||
}
|
||||
return($requestTokenArray['requesttoken']);
|
||||
return($requestToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* @see OC_Util::$callLifespan
|
||||
* @see OC_Util::callRegister()
|
||||
*/
|
||||
public static function isCallRegistered() {
|
||||
|
@ -530,7 +513,7 @@ class OC_Util {
|
|||
}
|
||||
|
||||
// Check if the token is valid
|
||||
if(!isset($_SESSION['requesttoken']) || time() > $_SESSION['requesttoken']["time"]) {
|
||||
if($token !== $_SESSION['requesttoken']) {
|
||||
// Not valid
|
||||
return false;
|
||||
} else {
|
||||
|
|
Загрузка…
Ссылка в новой задаче