added CSRF protection

This commit is contained in:
Roland Gruber 2015-05-14 09:18:45 +00:00
parent 1f0d4b0cda
commit c34b040766
10 changed files with 92 additions and 14 deletions

View File

@ -1,4 +1,5 @@
June 215 June 215
- Security: added CSRF protection
- Zarafa users: allow to change display format of "Send As" - Zarafa users: allow to change display format of "Send As"

View File

@ -591,12 +591,16 @@ class htmlInputField extends htmlElement {
'; ';
} }
if ($this->checkPasswordStrength) { if ($this->checkPasswordStrength) {
$ajaxPath = "../templates/misc/ajax.php"; $tokenSuffix = '?' . getSecurityTokenName() . '=' . getSecurityTokenValue();
if (isSelfService()) {
$tokenSuffix .= '&selfservice=1';
}
$ajaxPath = "../templates/misc/ajax.php" . $tokenSuffix;
if (is_file("../../templates/misc/ajax.php")) { if (is_file("../../templates/misc/ajax.php")) {
$ajaxPath = "../../templates/misc/ajax.php"; $ajaxPath = "../../templates/misc/ajax.php" . $tokenSuffix;
} }
elseif (is_file("../../../templates/misc/ajax.php")) { elseif (is_file("../../../templates/misc/ajax.php")) {
$ajaxPath = "../../../templates/misc/ajax.php"; $ajaxPath = "../../../templates/misc/ajax.php" . $tokenSuffix;
} }
echo '<script type="text/javascript"> echo '<script type="text/javascript">
checkPasswordStrength("' . $this->fieldName . '", "' . $ajaxPath . '"); checkPasswordStrength("' . $this->fieldName . '", "' . $ajaxPath . '");

View File

@ -1238,7 +1238,8 @@ class accountContainer {
$passwordButton = new htmlButton('accountContainerPassword', _('Set password')); $passwordButton = new htmlButton('accountContainerPassword', _('Set password'));
$passwordButton->setIconClass('passwordButton'); $passwordButton->setIconClass('passwordButton');
$passwordButton->setOnClick('passwordShowChangeDialog(\'' . _('Set password') . '\', \'' . _('Ok') . '\', \'' $passwordButton->setOnClick('passwordShowChangeDialog(\'' . _('Set password') . '\', \'' . _('Ok') . '\', \''
. _('Cancel') . '\', \'' . _('Set random password') . '\', \'../misc/ajax.php?function=passwordChange\');'); . _('Cancel') . '\', \'' . _('Set random password') . '\', \'../misc/ajax.php?function=passwordChange&'
. getSecurityTokenName() . '=' . getSecurityTokenValue() . '\');');
$leftButtonGroup->addElement($passwordButton); $leftButtonGroup->addElement($passwordButton);
} }
$table->addElement($leftButtonGroup); $table->addElement($leftButtonGroup);

View File

@ -2972,7 +2972,9 @@ class inetOrgPerson extends baseModule implements passwordService {
"action": "delete", "action": "delete",
"id": id "id": id
}; };
jQuery.post(\'../misc/ajax.php?selfservice=1&module=inetOrgPerson&scope=user\', {jsonInput: actionJSON}, function(data) {inetOrgPersonDeleteCertificateHandleReply(data);}, \'json\'); jQuery.post(\'../misc/ajax.php?selfservice=1&module=inetOrgPerson&scope=user'
. '&' . getSecurityTokenName() . '=' . getSecurityTokenValue()
. '\', {jsonInput: actionJSON}, function(data) {inetOrgPersonDeleteCertificateHandleReply(data);}, \'json\');
} }
function inetOrgPersonDeleteCertificateHandleReply(data) { function inetOrgPersonDeleteCertificateHandleReply(data) {
@ -2990,7 +2992,8 @@ class inetOrgPerson extends baseModule implements passwordService {
element: document.getElementById(elementID), element: document.getElementById(elementID),
listElement: uploadStatus, listElement: uploadStatus,
request: { request: {
endpoint: \'../misc/ajax.php?selfservice=1&module=inetOrgPerson&scope=user\', endpoint: \'../misc/ajax.php?selfservice=1&module=inetOrgPerson&scope=user'
. '&' . getSecurityTokenName() . '=' . getSecurityTokenValue() . '\',
forceMultipart: true, forceMultipart: true,
params: { params: {
action: \'ajaxCertUpload\' action: \'ajaxCertUpload\'

View File

@ -305,7 +305,9 @@ class ldapPublicKey extends baseModule {
for (c = 0; c < count; c++) { for (c = 0; c < count; c++) {
actionJSON["sshPublicKey_" + c] = jQuery(\'#sshPublicKey_\' + c).val(); actionJSON["sshPublicKey_" + c] = jQuery(\'#sshPublicKey_\' + c).val();
} }
jQuery.post(\'../misc/ajax.php?selfservice=1&module=ldapPublicKey&scope=user\', {jsonInput: actionJSON}, function(data) {ldapPublicKeyDeleteKeyHandleReply(data);}, \'json\'); jQuery.post(\'../misc/ajax.php?selfservice=1&module=ldapPublicKey&scope=user'
. '&' . getSecurityTokenName() . '=' . getSecurityTokenValue()
. '\', {jsonInput: actionJSON}, function(data) {ldapPublicKeyDeleteKeyHandleReply(data);}, \'json\');
} }
function ldapPublicKeyDeleteKeyHandleReply(data) { function ldapPublicKeyDeleteKeyHandleReply(data) {
@ -324,7 +326,9 @@ class ldapPublicKey extends baseModule {
for (c = 0; c < count; c++) { for (c = 0; c < count; c++) {
actionJSON["sshPublicKey_" + c] = jQuery(\'#sshPublicKey_\' + c).val(); actionJSON["sshPublicKey_" + c] = jQuery(\'#sshPublicKey_\' + c).val();
} }
jQuery.post(\'../misc/ajax.php?selfservice=1&module=ldapPublicKey&scope=user\', {jsonInput: actionJSON}, function(data) {ldapPublicKeyAddKeyHandleReply(data);}, \'json\'); jQuery.post(\'../misc/ajax.php?selfservice=1&module=ldapPublicKey&scope=user'
. '&' . getSecurityTokenName() . '=' . getSecurityTokenValue()
. '\', {jsonInput: actionJSON}, function(data) {ldapPublicKeyAddKeyHandleReply(data);}, \'json\');
} }
function ldapPublicKeyAddKeyHandleReply(data) { function ldapPublicKeyAddKeyHandleReply(data) {
@ -348,7 +352,8 @@ class ldapPublicKey extends baseModule {
element: document.getElementById(elementID), element: document.getElementById(elementID),
listElement: uploadStatus, listElement: uploadStatus,
request: { request: {
endpoint: \'../misc/ajax.php?selfservice=1&module=ldapPublicKey&scope=user\', endpoint: \'../misc/ajax.php?selfservice=1&module=ldapPublicKey&scope=user'
. '&' . getSecurityTokenName() . '=' . getSecurityTokenValue() . '\',
forceMultipart: true, forceMultipart: true,
paramsInBody: true, paramsInBody: true,
params: parameters params: parameters

View File

@ -3,7 +3,7 @@
$Id$ $Id$
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
Copyright (C) 2006 - 2014 Roland Gruber Copyright (C) 2006 - 2015 Roland Gruber
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -497,4 +497,55 @@ function getClientIPForLogging() {
return $ip; return $ip;
} }
/**
* Adds a security token to the session to prevent CSRF attacks.
*/
function addSecurityTokenToSession() {
$_SESSION[getSecurityTokenName()] = getRandomNumber();
}
/**
* Checks if the security token from SESSION matches POST data.
*
* @param $post use POST, set to false for GET (default: true)
*/
function validateSecurityToken($post = true) {
$vars = $post ? $_POST : $_GET;
if (empty($vars)) {
return;
}
if (empty($vars[getSecurityTokenName()]) || ($vars[getSecurityTokenName()] != $_SESSION[getSecurityTokenName()])) {
logNewMessage(LOG_ERR, 'Security token does not match POST data.');
die();
}
}
/**
* Adds a hidden input field to the given meta HTML table.
* Should be used to add token at the end of table.
*
* @param htmlTable $container table
*/
function addSecurityTokenToMetaHTML(&$container) {
$container->addElement(new htmlHiddenInput(getSecurityTokenName(), $_SESSION[getSecurityTokenName()]), true);
}
/**
* Returns the name of the security token parameter.
*
* @return String name
*/
function getSecurityTokenName() {
return 'sec_token';
}
/**
* Returns the value of the security token parameter.
*
* @return String value
*/
function getSecurityTokenValue() {
return $_SESSION[getSecurityTokenName()];
}
?> ?>

View File

@ -3,7 +3,7 @@
$Id$ $Id$
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
Copyright (C) 2006 - 2014 Roland Gruber Copyright (C) 2006 - 2015 Roland Gruber
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -285,6 +285,15 @@ function checkSelfServiceSettings($scope, &$options, &$profile) {
return $return; return $return;
} }
/**
* Returns if script runs inside self service.
*
* @return boolean is self service
*/
function isSelfService() {
return session_name() == 'SELFSERVICE';
}
/** /**
* Includes all settings of a self service profile. * Includes all settings of a self service profile.

View File

@ -560,7 +560,7 @@ function checkPasswordStrength(fieldID, ajaxURL) {
"password": value "password": value
}; };
// make AJAX call // make AJAX call
jQuery.post(ajaxURL + "?function=passwordStrengthCheck", {jsonInput: pwdJSON}, function(data) {checkPasswordStrengthHandleReply(data, fieldID);}, 'json'); jQuery.post(ajaxURL + "&function=passwordStrengthCheck", {jsonInput: pwdJSON}, function(data) {checkPasswordStrengthHandleReply(data, fieldID);}, 'json');
}; };
jQuery(field).keyup(check); jQuery(field).keyup(check);
} }

View File

@ -615,6 +615,7 @@ if(!empty($_POST['checklogin'])) {
$_SESSION['sec_session_id'] = session_id(); $_SESSION['sec_session_id'] = session_id();
$_SESSION['sec_client_ip'] = $_SERVER['REMOTE_ADDR']; $_SESSION['sec_client_ip'] = $_SERVER['REMOTE_ADDR'];
$_SESSION['sec_sessionTime'] = time(); $_SESSION['sec_sessionTime'] = time();
addSecurityTokenToSession();
// logging // logging
logNewMessage(LOG_NOTICE, 'User ' . $username . ' (' . $clientSource . ') successfully logged in.'); logNewMessage(LOG_NOTICE, 'User ' . $username . ' (' . $clientSource . ') successfully logged in.');
// Load main frame // Load main frame

View File

@ -3,7 +3,7 @@
$Id$ $Id$
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
Copyright (C) 2011 - 2014 Roland Gruber Copyright (C) 2011 - 2015 Roland Gruber
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -58,6 +58,9 @@ class lamAjax {
* Manages an AJAX request. * Manages an AJAX request.
*/ */
public static function handleRequest() { public static function handleRequest() {
// check token
validateSecurityToken(false);
if (isset($_GET['module']) && isset($_GET['scope']) && in_array($_GET['module'], getAvailableModules($_GET['scope']))) { if (isset($_GET['module']) && isset($_GET['scope']) && in_array($_GET['module'], getAvailableModules($_GET['scope']))) {
if (isset($_GET['useContainer']) && ($_GET['useContainer'] == '1')) { if (isset($_GET['useContainer']) && ($_GET['useContainer'] == '1')) {
if (!isset($_SESSION['account'])) die(); if (!isset($_SESSION['account'])) die();
@ -76,8 +79,8 @@ class lamAjax {
if (!isset($_POST['jsonInput'])) { if (!isset($_POST['jsonInput'])) {
die(); die();
} }
$jsonInput = $_POST['jsonInput']; $jsonInput = $_POST['jsonInput'];
if ($function == 'passwordChange') { if ($function == 'passwordChange') {
lamAjax::managePasswordChange($jsonInput); lamAjax::managePasswordChange($jsonInput);
} }