mirror of
https://github.com/Lastorder-DC/rhymix.git
synced 2026-04-02 01:52:10 +09:00
commit
72d9077b69
8 changed files with 123 additions and 13 deletions
|
|
@ -307,16 +307,35 @@ class Security
|
|||
*/
|
||||
public static function checkCSRF($referer = null)
|
||||
{
|
||||
if (!$referer)
|
||||
{
|
||||
$referer = strval($_SERVER['HTTP_REFERER']);
|
||||
}
|
||||
if (strval($referer) === '')
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return URL::isInternalURL($referer);
|
||||
elseif ($token = $_SERVER['HTTP_X_CSRF_TOKEN'])
|
||||
{
|
||||
return Session::verifyToken($token);
|
||||
}
|
||||
elseif ($token = \Context::get('_rx_csrf_token'))
|
||||
{
|
||||
return Session::verifyToken($token);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Session::getMemberSrl())
|
||||
{
|
||||
trigger_error('CSRF token missing in POST request: ' . (\Context::get('act') ?: '(no act)'), \E_USER_WARNING);
|
||||
}
|
||||
|
||||
$referer = strval($referer ?: $_SERVER['HTTP_REFERER']);
|
||||
if ($referer !== '')
|
||||
{
|
||||
return URL::isInternalURL($referer);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -378,6 +378,7 @@ class Session
|
|||
$_SESSION['RHYMIX']['timezone'] = DateTime::getTimezoneForCurrentUser();
|
||||
$_SESSION['RHYMIX']['secret'] = Security::getRandom(32, 'alnum');
|
||||
$_SESSION['RHYMIX']['tokens'] = array();
|
||||
$_SESSION['RHYMIX']['token'] = false;
|
||||
$_SESSION['is_webview'] = self::_isBuggyUserAgent();
|
||||
$_SESSION['is_new_session'] = true;
|
||||
$_SESSION['is_logged'] = false;
|
||||
|
|
@ -847,6 +848,26 @@ class Session
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a generic token that is not restricted to any particular key.
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function getGenericToken()
|
||||
{
|
||||
if (!self::isStarted())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$_SESSION['RHYMIX']['token'])
|
||||
{
|
||||
$_SESSION['RHYMIX']['token'] = self::createToken('');
|
||||
}
|
||||
|
||||
return $_SESSION['RHYMIX']['token'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a token that can only be verified in the same session.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
($.os.Linux) ? 'Linux' :
|
||||
($.os.Unix) ? 'Unix' :
|
||||
($.os.Mac) ? 'Mac' : '';
|
||||
|
||||
|
||||
/* Intercept getScript error due to broken minified script URL */
|
||||
$(document).ajaxError(function(event, jqxhr, settings, thrownError) {
|
||||
if(settings.dataType === "script" && (jqxhr.status >= 400 || (jqxhr.responseText && jqxhr.responseText.length < 40))) {
|
||||
|
|
@ -27,7 +27,56 @@
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @brief Check if two URLs belong to the same origin
|
||||
*/
|
||||
window.isSameOrigin = function(url1, url2, allow_relative_url2) {
|
||||
var a1 = $("<a>").attr("href", url1)[0];
|
||||
var a2 = $("<a>").attr("href", url2)[0];
|
||||
if (!a2.hostname && allow_relative_url2) {
|
||||
return true;
|
||||
}
|
||||
if (a1.protocol !== a2.protocol) return false;
|
||||
if (a1.hostname !== a2.hostname) return false;
|
||||
if (a1.port !== a2.port) return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get CSRF token for the document
|
||||
*/
|
||||
window.getCSRFToken = function() {
|
||||
return $("meta[name='csrf-token']").attr("content");
|
||||
};
|
||||
|
||||
/* Intercept jQuery AJAX calls to add CSRF headers */
|
||||
$.ajaxPrefilter(function(options) {
|
||||
if (!isSameOrigin(location.href, options.url, true)) return;
|
||||
var token = getCSRFToken();
|
||||
if (token) {
|
||||
if (!options.headers) options.headers = {};
|
||||
options.headers["X-CSRF-Token"] = token;
|
||||
}
|
||||
});
|
||||
|
||||
/* Add CSRF token to dynamically loaded forms */
|
||||
$.fn.addCSRFTokenToForm = function() {
|
||||
var token = getCSRFToken();
|
||||
if (token) {
|
||||
return $(this).each(function() {
|
||||
if ($(this).data("csrf-token-checked") === "Y") return;
|
||||
if (!isSameOrigin(location.href, $(this).attr("action"), true)) {
|
||||
return $(this).data("csrf-token-checked", "Y");
|
||||
}
|
||||
$("<input />").attr({ type: "hidden", name: "_rx_csrf_token", value: token }).appendTo($(this));
|
||||
return $(this).data("csrf-token-checked", "Y");
|
||||
});
|
||||
} else {
|
||||
return $(this);
|
||||
}
|
||||
};
|
||||
|
||||
/* Array for pending debug data */
|
||||
window.rhymix_debug_pending_data = [];
|
||||
|
||||
|
|
@ -154,6 +203,13 @@
|
|||
/* jQuery(document).ready() */
|
||||
jQuery(function($) {
|
||||
|
||||
/* CSRF token */
|
||||
$("form[method]").filter(function() { return this.method.toUpperCase() == "POST"; }).addCSRFTokenToForm();
|
||||
$(document).on("submit", "form[method='post']", $.fn.addCSRFTokenToForm);
|
||||
$(document).on("focus", "input,select,textarea", function() {
|
||||
$(this).parents("form[method]").filter(function() { return this.method.toUpperCase() == "POST"; }).addCSRFTokenToForm();
|
||||
});
|
||||
|
||||
/* select - option의 disabled=disabled 속성을 IE에서도 체크하기 위한 함수 */
|
||||
if(navigator.userAgent.match(/MSIE/)) {
|
||||
$('select').each(function(i, sels) {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
params.module = module;
|
||||
params.act = act;
|
||||
params._rx_ajax_compat = 'XMLRPC';
|
||||
params._rx_csrf_token = getCSRFToken();
|
||||
|
||||
// Fill in the XE vid.
|
||||
if (typeof(xeVid) != "undefined") params.vid = xeVid;
|
||||
|
|
@ -46,9 +47,7 @@
|
|||
}
|
||||
|
||||
// Check whether this is a cross-domain request. If so, use an alternative method.
|
||||
var _u1 = $("<a>").attr("href", location.href)[0];
|
||||
var _u2 = $("<a>").attr("href", url)[0];
|
||||
if (_u1.protocol != _u2.protocol || _u1.port != _u2.port) return send_by_form(url, params);
|
||||
if (!isSameOrigin(location.href, url)) return send_by_form(url, params);
|
||||
|
||||
// Delay the waiting message for 1 second to prevent rapid blinking.
|
||||
waiting_obj.css("opacity", 0.0);
|
||||
|
|
@ -172,6 +171,7 @@
|
|||
params.module = action[0];
|
||||
params.act = action[1];
|
||||
params._rx_ajax_compat = 'JSON';
|
||||
params._rx_csrf_token = getCSRFToken();
|
||||
|
||||
// Fill in the XE vid.
|
||||
if (typeof(xeVid) != "undefined") params.vid = xeVid;
|
||||
|
|
@ -278,6 +278,7 @@
|
|||
//if (action.length != 2) return;
|
||||
params.module = action[0];
|
||||
params.act = action[1];
|
||||
params._rx_csrf_token = getCSRFToken();
|
||||
|
||||
// Fill in the XE vid.
|
||||
if (typeof(xeVid) != "undefined") params.vid = xeVid;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
<block loop="Context::getMetaTag() => $no, $val">
|
||||
<meta http-equiv="{$val['name']}"|cond="$val['is_http_equiv']" name="{$val['name']}"|cond="!$val['is_http_equiv']" content="{$val['content']}" />
|
||||
</block>
|
||||
<meta name="csrf-token" content="{($is_logged || $act) ? \Rhymix\Framework\Session::getGenericToken() : ''}" />
|
||||
|
||||
<!-- TITLE -->
|
||||
<title>{Context::getBrowserTitle()}</title>
|
||||
|
|
|
|||
3
modules/editor/tpl/js/uploader.js
Executable file → Normal file
3
modules/editor/tpl/js/uploader.js
Executable file → Normal file
|
|
@ -54,7 +54,8 @@ var uploadAutosaveChecker = false;
|
|||
mid : current_mid,
|
||||
act : 'procFileUpload',
|
||||
editor_sequence : seq,
|
||||
uploadTargetSrl : editorRelKeys[seq].primary.value
|
||||
uploadTargetSrl : editorRelKeys[seq].primary.value,
|
||||
_rx_csrf_token : getCSRFToken()
|
||||
},
|
||||
http_success : [302],
|
||||
file_size_limit : Math.floor( (parseInt(cfg.allowedFileSize,10)||1024) / 1024 ),
|
||||
|
|
|
|||
|
|
@ -106,17 +106,21 @@ class SecurityTest extends \Codeception\TestCase\Test
|
|||
|
||||
public function testCheckCSRF()
|
||||
{
|
||||
$error_reporting = error_reporting(0);
|
||||
|
||||
$_SERVER['REQUEST_METHOD'] = 'GET';
|
||||
$_SERVER['HTTP_REFERER'] = '';
|
||||
$this->assertTrue(Rhymix\Framework\Security::checkCSRF());
|
||||
|
||||
$_SERVER['REQUEST_METHOD'] = 'POST';
|
||||
$this->assertTrue(Rhymix\Framework\Security::checkCSRF());
|
||||
$this->assertFalse(Rhymix\Framework\Security::checkCSRF());
|
||||
|
||||
$_SERVER['HTTP_REFERER'] = 'http://www.foobar.com/';
|
||||
$this->assertFalse(Rhymix\Framework\Security::checkCSRF());
|
||||
|
||||
$this->assertTrue(Rhymix\Framework\Security::checkCSRF('http://www.rhymix.org/'));
|
||||
|
||||
error_reporting($error_reporting);
|
||||
}
|
||||
|
||||
public function testCheckXEE()
|
||||
|
|
|
|||
|
|
@ -334,9 +334,16 @@ class SessionTest extends \Codeception\TestCase\Test
|
|||
$this->assertFalse(Rhymix\Framework\Session::verifyToken($token2, '/wrong/key'));
|
||||
$this->assertFalse(Rhymix\Framework\Session::verifyToken(strrev($token2)));
|
||||
|
||||
$token3 = Rhymix\Framework\Session::getGenericToken();
|
||||
$this->assertEquals(16, strlen($token3));
|
||||
$this->assertTrue(Rhymix\Framework\Session::verifyToken($token3));
|
||||
$this->assertTrue(Rhymix\Framework\Session::verifyToken($token3, ''));
|
||||
$this->assertFalse(Rhymix\Framework\Session::verifyToken($token3, '/wrong/key'));
|
||||
|
||||
Rhymix\Framework\Session::destroy();
|
||||
$this->assertFalse(Rhymix\Framework\Session::verifyToken($token1));
|
||||
$this->assertFalse(Rhymix\Framework\Session::verifyToken($token, '/my/key'));
|
||||
$this->assertFalse(Rhymix\Framework\Session::getGenericToken());
|
||||
}
|
||||
|
||||
public function testEncryption()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue