MDL-18039 bacporting security overview report to 1.8.x

This commit is contained in:
skodak
2009-02-15 17:28:55 +00:00
parent b74316986b
commit 66fbfc95b7
5 changed files with 1041 additions and 0 deletions
+121
View File
@@ -0,0 +1,121 @@
<?php //$Id$
///////////////////////////////////////////////////////////////////////////
// //
// NOTICE OF COPYRIGHT //
// //
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
// http://moodle.org //
// //
// Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com //
// //
// 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 //
// the Free Software Foundation; either version 2 of the License, or //
// (at your option) any later version. //
// //
// This program 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 General Public License for more details: //
// //
// http://www.gnu.org/copyleft/gpl.html //
// //
///////////////////////////////////////////////////////////////////////////
require_once('../../../config.php');
require_once($CFG->dirroot.'/'.$CFG->admin.'/report/security/lib.php');
require_once($CFG->libdir.'/adminlib.php');
require_login();
$issue = optional_param('issue', '', PARAM_FILE); // show detailed info about one issue only
$issues = report_security_get_issue_list();
// test if issue valid string
if (array_search($issue, $issues, true) === false) {
$issue = '';
}
// we may need a bit more memory and this may take a long time to process
@raise_memory_limit('128M');
@set_time_limit(0);
// Print the header.
$adminroot = admin_get_root();
admin_externalpage_setup('reportsecurity', $adminroot);
admin_externalpage_print_header($adminroot);
print_heading(get_string('reportsecurity', 'report_security'));
while(@ob_end_flush());
@flush();
$strok = '<span class="statusok">'.get_string('statusok', 'report_security').'</span>';
$strinfo = '<span class="statusinfo">'.get_string('statusinfo', 'report_security').'</span>';
$strwarning = '<span class="statuswarning">'.get_string('statuswarning', 'report_security').'</span>';
$strserious = '<span class="statusserious">'.get_string('statusserious', 'report_security').'</span>';
$strcritical = '<span class="statuscritical">'.get_string('statuscritical', 'report_security').'</span>';
$strissue = get_string('issue', 'report_security');
$strstatus = get_string('status', 'report_security');
$strdesc = get_string('description', 'report_security');
$strconfig = get_string('configuration', 'report_security');
$statusarr = array(REPORT_SECURITY_OK => $strok,
REPORT_SECURITY_INFO => $strinfo,
REPORT_SECURITY_WARNING => $strwarning,
REPORT_SECURITY_SERIOUS => $strserious,
REPORT_SECURITY_CRITICAL => $strcritical);
$url = "$CFG->wwwroot/$CFG->admin/report/security/index.php";
if ($issue and ($result = $issue(true))) {
$table = new object();
$table->head = array($strissue, $strstatus, $strdesc, $strconfig);
$table->size = array('30%', '10%', '50%', '10%' );
$table->align = array('left', 'left', 'left', 'left');
$table->width = '90%';
$table->data = array();
// print detail of one issue only
$row = array();
$row[0] = report_security_doc_link($issue, $result->name);
$row[1] = $statusarr[$result->status];
$row[2] = $result->info;
$row[3] = is_null($result->link) ? '&nbsp;' : $result->link;
$table->data[] = $row;
print_table($table);
print_box($result->details, 'generalbox boxwidthnormal boxaligncenter'); // TODO: add proper css
print_continue($url);
} else {
$table = new object();
$table->head = array($strissue, $strstatus, $strdesc);
$table->size = array('30%', '10%', '60%' );
$table->align = array('left', 'left', 'left');
$table->width = '90%';
$table->data = array();
foreach ($issues as $issue) {
$result = $issue(false);
if (!$result) {
// ignore this test
continue;
}
$row = array();
$row[0] = "<a href='$url?issue=$result->issue'>$result->name</a>";
$row[1] = $statusarr[$result->status];
$row[2] = $result->info;
$table->data[] = $row;
}
print_table($table);
}
admin_externalpage_print_footer($adminroot);
+729
View File
@@ -0,0 +1,729 @@
<?php //$Id$
///////////////////////////////////////////////////////////////////////////
// //
// NOTICE OF COPYRIGHT //
// //
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
// http://moodle.org //
// //
// Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com //
// //
// 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 //
// the Free Software Foundation; either version 2 of the License, or //
// (at your option) any later version. //
// //
// This program 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 General Public License for more details: //
// //
// http://www.gnu.org/copyleft/gpl.html //
// //
///////////////////////////////////////////////////////////////////////////
require_once("$CFG->libdir/adminlib.php");
define('REPORT_SECURITY_OK', 'ok');
define('REPORT_SECURITY_INFO', 'info');
define('REPORT_SECURITY_WARNING', 'warning');
define('REPORT_SECURITY_SERIOUS', 'serious');
define('REPORT_SECURITY_CRITICAL', 'critical');
function report_security_get_issue_list() {
return array(
'report_security_check_globals',
'report_security_check_unsecuredataroot',
'report_security_check_displayerrors',
'report_security_check_noauth',
'report_security_check_embed',
'report_security_check_mediafilterswf',
'report_security_check_openprofiles',
'report_security_check_google',
'report_security_check_configrw',
'report_security_check_defaultuserrole',
'report_security_check_guestrole',
'report_security_check_defaultcourserole',
'report_security_check_courserole',
);
}
function report_security_doc_link($issue, $name) {
global $CFG;
if (empty($CFG->docroot)) {
return $name;
}
$lang = str_replace('_utf8', '', current_language());
$str = "<a onclick=\"this.target='docspopup'\" href=\"$CFG->docroot/$lang/report/security/$issue\">";
$str .= "<img class=\"iconhelp\" src=\"$CFG->httpswwwroot/pix/docs.gif\" alt=\"\" />$name</a>";
return $str;
}
///=============================================
/// Issue checks
///=============================================
/**
* Verifies register globals PHP setting.
* @param bool $detailed
* @return object result
*/
function report_security_check_globals($detailed=false) {
$result = new object();
$result->issue = 'report_security_check_globals';
$result->name = get_string('check_globals_name', 'report_security');
$result->info = null;
$result->details = null;
$result->status = null;
$result->link = null;
if (ini_get_bool('register_globals')) {
$result->status = REPORT_SECURITY_CRITICAL;
$result->info = get_string('check_globals_error', 'report_security');
} else {
$result->status = REPORT_SECURITY_OK;
$result->info = get_string('check_globals_ok', 'report_security');
}
if ($detailed) {
$result->details = get_string('check_globals_details', 'report_security');
}
return $result;
}
/**
* Verifies unsupported noauth setting
* @param bool $detailed
* @return object result
*/
function report_security_check_noauth($detailed=false) {
global $CFG;
$result = new object();
$result->issue = 'report_security_check_noauth';
$result->name = get_string('check_noauth_name', 'report_security');
$result->info = null;
$result->details = null;
$result->status = null;
$result->link = null;
$result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/auth.php\">".get_string('authentication').'</a>';
if (is_enabled_auth('none')) {
$result->status = REPORT_SECURITY_CRITICAL;
$result->info = get_string('check_noauth_error', 'report_security');
} else {
$result->status = REPORT_SECURITY_OK;
$result->info = get_string('check_noauth_ok', 'report_security');
}
if ($detailed) {
$result->details = get_string('check_noauth_details', 'report_security');
}
return $result;
}
/**
* Verifies sloppy embedding - this should have been removed long ago!!
* @param bool $detailed
* @return object result
*/
function report_security_check_embed($detailed=false) {
global $CFG;
$result = new object();
$result->issue = 'report_security_check_embed';
$result->name = get_string('check_embed_name', 'report_security');
$result->info = null;
$result->details = null;
$result->status = null;
$result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies\">".get_string('sitepolicies', 'admin').'</a>';
if (!empty($CFG->allowobjectembed)) {
$result->status = REPORT_SECURITY_CRITICAL;
$result->info = get_string('check_embed_error', 'report_security');
} else {
$result->status = REPORT_SECURITY_OK;
$result->info = get_string('check_embed_ok', 'report_security');
}
if ($detailed) {
$result->details = get_string('check_embed_details', 'report_security');
}
return $result;
}
/**
* Verifies sloppy swf embedding - this should have been removed long ago!!
* @param bool $detailed
* @return object result
*/
function report_security_check_mediafilterswf($detailed=false) {
global $CFG;
$result = new object();
$result->issue = 'report_security_check_mediafilterswf';
$result->name = get_string('check_mediafilterswf_name', 'report_security');
$result->info = null;
$result->details = null;
$result->status = null;
$result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/filters.php\">".get_string('filtersettings', 'admin').'</a>';
if (!empty($CFG->textfilters)) {
$activefilters = explode(',', $CFG->textfilters);
} else {
$activefilters = array();
}
if (array_search('filter/mediaplugin', $activefilters) !== false and !empty($CFG->filter_mediaplugin_enable_swf)) {
$result->status = REPORT_SECURITY_CRITICAL;
$result->info = get_string('check_mediafilterswf_error', 'report_security');
} else {
$result->status = REPORT_SECURITY_OK;
$result->info = get_string('check_mediafilterswf_ok', 'report_security');
}
if ($detailed) {
$result->details = get_string('check_mediafilterswf_details', 'report_security');
}
return $result;
}
/**
* Verifies fatal misconfiguration of dataroot
* @param bool $detailed
* @return object result
*/
function report_security_check_unsecuredataroot($detailed=false) {
global $CFG;
$result = new object();
$result->issue = 'report_security_check_unsecuredataroot';
$result->name = get_string('check_unsecuredataroot_name', 'report_security');
$result->info = null;
$result->details = null;
$result->status = null;
$result->link = null;
$insecuredataroot = is_dataroot_insecure();
if ($insecuredataroot) {
$result->status = REPORT_SECURITY_SERIOUS;
$result->info = get_string('check_unsecuredataroot_warning', 'report_security', $CFG->dataroot);
} else {
$result->status = REPORT_SECURITY_OK;
$result->info = get_string('check_unsecuredataroot_ok', 'report_security');
}
if ($detailed) {
$result->details = get_string('check_unsecuredataroot_details', 'report_security');
}
return $result;
}
/**
* Verifies disaplying of errors - problem for lib files and 3rd party code
* because we can not disable debugging in these scripts (they do not include config.php)
* @param bool $detailed
* @return object result
*/
function report_security_check_displayerrors($detailed=false) {
$result = new object();
$result->issue = 'report_security_check_displayerrors';
$result->name = get_string('check_displayerrors_name', 'report_security');
$result->info = null;
$result->details = null;
$result->status = null;
$result->link = null;
if (defined('WARN_DISPLAY_ERRORS_ENABLED')) {
$result->status = REPORT_SECURITY_WARNING;
$result->info = get_string('check_displayerrors_error', 'report_security');
} else {
$result->status = REPORT_SECURITY_OK;
$result->info = get_string('check_displayerrors_ok', 'report_security');
}
if ($detailed) {
$result->details = get_string('check_displayerrors_details', 'report_security');
}
return $result;
}
/**
* Verifies open profiles - originaly open by default, not anymore because spammer abused it a lot
* @param bool $detailed
* @return object result
*/
function report_security_check_openprofiles($detailed=false) {
global $CFG;
$result = new object();
$result->issue = 'report_security_check_openprofiles';
$result->name = get_string('check_openprofiles_name', 'report_security');
$result->info = null;
$result->details = null;
$result->status = null;
$result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies\">".get_string('sitepolicies', 'admin').'</a>';
if (empty($CFG->forcelogin) and empty($CFG->forceloginforprofiles)) {
$result->status = REPORT_SECURITY_WARNING;
$result->info = get_string('check_openprofiles_error', 'report_security');
} else {
$result->status = REPORT_SECURITY_OK;
$result->info = get_string('check_openprofiles_ok', 'report_security');
}
if ($detailed) {
$result->details = get_string('check_openprofiles_details', 'report_security');
}
return $result;
}
/**
* Verifies google access not combined with disabled guest access
* because attackers might gain guest access by modifying browser signature.
* @param bool $detailed
* @return object result
*/
function report_security_check_google($detailed=false) {
global $CFG;
$result = new object();
$result->issue = 'report_security_check_google';
$result->name = get_string('check_google_name', 'report_security');
$result->info = null;
$result->details = null;
$result->status = null;
$result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies\">".get_string('sitepolicies', 'admin').'</a>';
if (empty($CFG->opentogoogle)) {
$result->status = REPORT_SECURITY_OK;
$result->info = get_string('check_google_ok', 'report_security');
} else if (!empty($CFG->guestloginbutton)) {
$result->status = REPORT_SECURITY_INFO;
$result->info = get_string('check_google_info', 'report_security');
} else {
$result->status = REPORT_SECURITY_SERIOUS;
$result->info = get_string('check_google_error', 'report_security');
}
if ($detailed) {
$result->details = get_string('check_google_details', 'report_security');
}
return $result;
}
/**
* Verifies config.php is not writable anymore after installation,
* config files were changed on several outdated server.
* @param bool $detailed
* @return object result
*/
function report_security_check_configrw($detailed=false) {
global $CFG;
$result = new object();
$result->issue = 'report_security_check_configrw';
$result->name = get_string('check_configrw_name', 'report_security');
$result->info = null;
$result->details = null;
$result->status = null;
$result->link = null;
if (is_writable($CFG->dirroot.'/config.php')) {
$result->status = REPORT_SECURITY_WARNING;
$result->info = get_string('check_configrw_warning', 'report_security');
} else {
$result->status = REPORT_SECURITY_OK;
$result->info = get_string('check_configrw_ok', 'report_security');
}
if ($detailed) {
$result->details = get_string('check_configrw_details', 'report_security');
}
return $result;
}
/**
* Verifies sanity of default user role.
* @param bool $detailed
* @return object result
*/
function report_security_check_defaultuserrole($detailed=false) {
global $CFG;
$result = new object();
$result->issue = 'report_security_check_defaultuserrole';
$result->name = get_string('check_defaultuserrole_name', 'report_security');
$result->info = null;
$result->details = null;
$result->status = null;
$result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=userpolicies\">".get_string('userpolicies', 'admin').'</a>';;
if (!$default_role = get_record('role', 'id', $CFG->defaultuserroleid)) {
$result->status = REPORT_SECURITY_WARNING;
$result->info = get_string('check_defaultuserrole_notset', 'report_security');
$result->details = $result->info;
return $result;
}
// first test if do anything enabled - that would be really crazy!
$sql = "SELECT COUNT(DISTINCT rc.contextid)
FROM {$CFG->prefix}role_capabilities rc
WHERE rc.capability = 'moodle/site:doanything'
AND rc.permission = ".CAP_ALLOW."
AND rc.roleid = $default_role->id";
$anythingcount = count_records_sql($sql);
// risky caps - usually very dangerous
$sql = "SELECT COUNT(DISTINCT rc.contextid)
FROM {$CFG->prefix}role_capabilities rc
JOIN {$CFG->prefix}capabilities cap ON cap.name = rc.capability
WHERE ".sql_bitand('cap.riskbitmask', (RISK_XSS | RISK_CONFIG))." <> 0
AND rc.permission = ".CAP_ALLOW."
AND rc.roleid = $default_role->id";
$riskycount = count_records_sql($sql);
// default role can not have view cap in all courses - this would break moodle badly
$viewcap = record_exists('role_capabilities', 'roleid', $default_role->id, 'permission', CAP_ALLOW, 'capability', 'moodle/course:view');
// it may have either no or 'user' legacy type - nothing else, or else it would break during upgrades badly
$legacyok = false;
$sql = "SELECT rc.capability, 1
FROM {$CFG->prefix}role_capabilities rc
WHERE rc.capability LIKE 'moodle/legacy:%'
AND rc.permission = ".CAP_ALLOW."
AND rc.roleid = $default_role->id";
$legacycaps = get_records_sql($sql);
if (!$legacycaps) {
$legacyok = true;
} else if (count($legacycaps) == 1 and isset($legacycaps['moodle/legacy:user'])) {
$legacyok = true;
}
if ($anythingcount or $riskycount or $viewcap or !$legacyok) {
$result->status = REPORT_SECURITY_CRITICAL;
$result->info = get_string('check_defaultuserrole_error', 'report_security', format_string($default_role->name));
} else {
$result->status = REPORT_SECURITY_OK;
$result->info = get_string('check_defaultuserrole_ok', 'report_security');
}
if ($detailed) {
$result->details = get_string('check_defaultuserrole_details', 'report_security');
}
return $result;
}
/**
* Verifies sanity of guest role
* @param bool $detailed
* @return object result
*/
function report_security_check_guestrole($detailed=false) {
global $CFG;
$result = new object();
$result->issue = 'report_security_check_guestrole';
$result->name = get_string('check_guestrole_name', 'report_security');
$result->info = null;
$result->details = null;
$result->status = null;
$result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=userpolicies\">".get_string('userpolicies', 'admin').'</a>';;
if (!$guest_role = get_record('role', 'id', $CFG->guestroleid)) {
$result->status = REPORT_SECURITY_WARNING;
$result->info = get_string('check_guestrole_notset', 'report_security');
$result->details = $result->info;
return $result;
}
// first test if do anything enabled - that would be really crazy!
$sql = "SELECT COUNT(DISTINCT rc.contextid)
FROM {$CFG->prefix}role_capabilities rc
WHERE rc.capability = 'moodle/site:doanything'
AND rc.permission = ".CAP_ALLOW."
AND rc.roleid = $guest_role->id";
$anythingcount = count_records_sql($sql);
// risky caps - usually very dangerous
$sql = "SELECT COUNT(DISTINCT rc.contextid)
FROM {$CFG->prefix}role_capabilities rc
JOIN {$CFG->prefix}capabilities cap ON cap.name = rc.capability
WHERE ".sql_bitand('cap.riskbitmask', (RISK_XSS | RISK_CONFIG))." <> 0
AND rc.permission = ".CAP_ALLOW."
AND rc.roleid = $guest_role->id";
$riskycount = count_records_sql($sql);
// it may have either no or 'guest' legacy type - nothing else, or else it would break during upgrades badly
$legacyok = false;
$sql = "SELECT rc.capability, 1
FROM {$CFG->prefix}role_capabilities rc
WHERE rc.capability LIKE 'moodle/legacy:%'
AND rc.permission = ".CAP_ALLOW."
AND rc.roleid = $guest_role->id";
$legacycaps = get_records_sql($sql);
if (!$legacycaps) {
$legacyok = true;
} else if (count($legacycaps) == 1 and isset($legacycaps['moodle/legacy:guest'])) {
$legacyok = true;
}
if ($anythingcount or $riskycount or !$legacyok) {
$result->status = REPORT_SECURITY_CRITICAL;
$result->info = get_string('check_guestrole_error', 'report_security', format_string($guest_role->name));
} else {
$result->status = REPORT_SECURITY_OK;
$result->info = get_string('check_guestrole_ok', 'report_security');
}
if ($detailed) {
$result->details = get_string('check_guestrole_details', 'report_security');
}
return $result;
}
/**
* Verifies sanity of site default course role.
* @param bool $detailed
* @return object result
*/
function report_security_check_defaultcourserole($detailed=false) {
global $CFG;
$problems = array();
$result = new object();
$result->issue = 'report_security_check_defaultcourserole';
$result->name = get_string('check_defaultcourserole_name', 'report_security');
$result->info = null;
$result->details = null;
$result->status = null;
$result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=userpolicies\">".get_string('userpolicies', 'admin').'</a>';;
if ($detailed) {
$result->details = get_string('check_defaultcourserole_details', 'report_security');
}
if (!$student_role = get_record('role', 'id', $CFG->defaultcourseroleid)) {
$result->status = REPORT_SECURITY_WARNING;
$result->info = get_string('check_defaultcourserole_notset', 'report_security');
$result->details = get_string('check_defaultcourserole_details', 'report_security');
return $result;
}
// first test if do anything enabled - that would be really crazy!
$sql = "SELECT DISTINCT rc.contextid
FROM {$CFG->prefix}role_capabilities rc
WHERE rc.capability = 'moodle/site:doanything'
AND rc.permission = ".CAP_ALLOW."
AND rc.roleid = $student_role->id";
if ($anything_contexts = get_records_sql($sql)) {
foreach($anything_contexts as $contextid) {
if ($contextid == SYSCONTEXTID) {
$a = "$CFG->wwwroot/$CFG->admin/roles/manage.php?action=view&roleid=$CFG->defaultcourseroleid";
} else {
$a = "$CFG->wwwroot/$CFG->admin/roles/override.php?contextid=$contextid&roleid=$CFG->defaultcourseroleid";
}
$problems[] = get_string('check_defaultcourserole_anything', 'report_security', $a);
}
}
// risky caps - usually very dangerous
$sql = "SELECT DISTINCT rc.contextid
FROM {$CFG->prefix}role_capabilities rc
JOIN {$CFG->prefix}capabilities cap ON cap.name = rc.capability
WHERE ".sql_bitand('cap.riskbitmask', (RISK_XSS | RISK_CONFIG))." <> 0
AND rc.permission = ".CAP_ALLOW."
AND rc.roleid = $student_role->id";
if ($riskycontexts = get_records_sql($sql)) {
foreach($riskycontexts as $contextid=>$unused) {
if ($contextid == SYSCONTEXTID) {
$a = "$CFG->wwwroot/$CFG->admin/roles/manage.php?action=view&roleid=$CFG->defaultcourseroleid";
} else {
$a = "$CFG->wwwroot/$CFG->admin/roles/override.php?contextid=$contextid&roleid=$CFG->defaultcourseroleid";
}
$problems[] = get_string('check_defaultcourserole_risky', 'report_security', $a);
}
}
// course creator or administrator does not make any sense here
$sql = "SELECT rc.capability, 1
FROM {$CFG->prefix}role_capabilities rc
WHERE rc.capability LIKE 'moodle/legacy:%'
AND rc.permission = ".CAP_ALLOW."
AND rc.roleid = $student_role->id";
$legacycaps = get_records_sql($sql);
if (isset($legacycaps['moodle/legacy:coursecreator']) or isset($legacycaps['moodle/legacy:admin'])) {
$problems[] = get_string('check_defaultcourserole_legacy', 'report_security');
}
if ($problems) {
$result->status = REPORT_SECURITY_CRITICAL;
$result->info = get_string('check_defaultcourserole_error', 'report_security', format_string($student_role->name));
if ($detailed) {
$result->details .= "<ul>";
foreach ($problems as $problem) {
$result->details .= "<li>$problem</li>";
}
$result->details .= "</ul>";
}
} else {
$result->status = REPORT_SECURITY_OK;
$result->info = get_string('check_defaultcourserole_ok', 'report_security');
}
return $result;
}
/**
* Verifies sanity of default roles in courses.
* @param bool $detailed
* @return object result
*/
function report_security_check_courserole($detailed=false) {
global $CFG, $SITE;
$problems = array();
$result = new object();
$result->issue = 'report_security_check_courserole';
$result->name = get_string('check_courserole_name', 'report_security');
$result->info = null;
$result->details = null;
$result->status = null;
$result->link = null;
if ($detailed) {
$result->details = get_string('check_courserole_details', 'report_security');
}
// get list of all student roles selected in courses excluding the default course role
$sql = "SELECT r.*
FROM {$CFG->prefix}role r
JOIN {$CFG->prefix}course c ON c.defaultrole = r.id
WHERE c.id <> $SITE->id AND r.id <> $CFG->defaultcourseroleid";
if (!$student_roles = get_records_sql($sql)) {
$result->status = REPORT_SECURITY_OK;
$result->info = get_string('check_courserole_notyet', 'report_security');
$result->details = get_string('check_courserole_details', 'report_security');
return $result;
}
$roleids = array_keys($student_roles);
// first test if do anything enabled - that would be really crazy!!!!!!
$inroles = implode(',', $roleids);
$sql = "SELECT rc.roleid, rc.contextid
FROM {$CFG->prefix}role_capabilities rc
WHERE rc.capability = 'moodle/site:doanything'
AND rc.permission = ".CAP_ALLOW."
AND rc.roleid IN ($inroles)
GROUP BY rc.roleid, rc.contextid
ORDER BY rc.roleid, rc.contextid";
$rs = get_recordset_sql($sql);
while ($res = rs_fetch_next_record($rs)) {
$roleid = $res->roleid;
$contextid = $res->contextid;
if ($contextid == SYSCONTEXTID) {
$a = "$CFG->wwwroot/$CFG->admin/roles/manage.php?action=view&roleid=$roleid";
} else {
$a = "$CFG->wwwroot/$CFG->admin/roles/override.php?contextid=$contextid&roleid=$roleid";
}
$problems[] = get_string('check_courserole_anything', 'report_security', $a);
}
rs_close($rs);
// risky caps in any level - usually very dangerous!!
$inroles = implode(',', $roleids);
$sql = "SELECT rc.roleid, rc.contextid
FROM {$CFG->prefix}role_capabilities rc
JOIN {$CFG->prefix}capabilities cap ON cap.name = rc.capability
WHERE ".sql_bitand('cap.riskbitmask', (RISK_XSS | RISK_CONFIG))." <> 0
AND rc.permission = ".CAP_ALLOW."
AND rc.roleid IN ($inroles)
GROUP BY rc.roleid, rc.contextid
ORDER BY rc.roleid, rc.contextid";
$rs = get_recordset_sql($sql);
while ($res = rs_fetch_next_record($rs)) {
$roleid = $res->roleid;
$contextid = $res->contextid;
if ($contextid == SYSCONTEXTID) {
$a = "$CFG->wwwroot/$CFG->admin/roles/manage.php?action=view&roleid=$roleid";
} else {
$a = "$CFG->wwwroot/$CFG->admin/roles/override.php?contextid=$contextid&roleid=$roleid";
}
$problems[] = get_string('check_courserole_risky', 'report_security', $a);
}
rs_close($rs);
// course creator or administrator does not make any sense here!
$inroles = implode(',', $roleids);
$sql = "SELECT DISTINCT rc.roleid
FROM {$CFG->prefix}role_capabilities rc
WHERE (rc.capability = 'moodle/legacy:coursecreator' OR rc.capability = 'moodle/legacy:admin')
AND rc.permission = ".CAP_ALLOW."
AND rc.roleid IN ($inroles)";
if ($legacys = get_records_sql($sql)) {
foreach ($legacys as $roleid=>$unused) {
$a = "$CFG->wwwroot/$CFG->admin/roles/manage.php?action=view&roleid=$roleid";
$problems[] = get_string('check_defaultcourserole_legacy', 'report_security', $a);
}
}
if ($problems) {
$result->status = REPORT_SECURITY_CRITICAL;
$result->info = get_string('check_courserole_error', 'report_security');
if ($detailed) {
$result->details .= "<ul>";
foreach ($problems as $problem) {
$result->details .= "<li>$problem</li>";
}
$result->details .= "</ul>";
}
} else {
$result->status = REPORT_SECURITY_OK;
$result->info = get_string('check_courserole_ok', 'report_security');
}
return $result;
}
+140
View File
@@ -0,0 +1,140 @@
<?PHP // $Id$
//NOTE TO TRANSLATORS: please do not translate yet, we are going to finalise this file sometime in January and backport to 1.9.x ;-)
$string['configuration'] = 'Configuration';
$string['details'] = 'Details';
$string['description'] = 'Description';
$string['issue'] = 'Issue';
$string['reportsecurity'] = 'Security overview';
$string['security:view'] = 'View security report';
$string['status'] = 'Status';
$string['statuscritical'] = 'Critical';
$string['statusinfo'] = 'Information';
$string['statusok'] = 'OK';
$string['statusserious'] = 'Serious';
$string['statuswarning'] = 'Warning';
$string['timewarning'] = 'Data processing may take a long time, please be patient...';
$string['check_configrw_details'] = '<p>It is recommended that the file permissions of config.php are changed after installation so that the file cannot be modified by the web server.
Please note that this measure does not improve security of the server significantly, though it may slow down or limit general exploits.</p>';
$string['check_configrw_name'] = 'Writable config.php';
$string['check_configrw_ok'] = 'config.php can not be modified by PHP scripts.';
$string['check_configrw_warning'] = 'PHP scripts may modify config.php.';
$string['check_cookiesecure_details'] = '<p>If you enable https communication it is recommended that you also enable secure cookies. You should also add permanent redirection from http to https.</p>';
$string['check_cookiesecure_error'] = 'Please enable secure cookies';
$string['check_cookiesecure_name'] = 'Secure cookies';
$string['check_cookiesecure_ok'] = 'Secure cookies enabled.';
$string['check_courserole_anything'] = 'The \"doanything\" capability must not be allowed in this <a href=\"$a\">context</a>.';
$string['check_courserole_details'] = '<p>Each course has one default enrolment role specified. Please make sure no risky capabilities are allowed for this role.</p>
<p>The only supported legacy type for the default course role is <em>Student</em>.</p>';
$string['check_courserole_error'] = 'Incorrectly defined default course roles detected!';
$string['check_courserole_legacy'] = 'Unsupported legacy type detected in the <a href=\"$a\">role</a>.';
$string['check_courserole_name'] = 'Default roles (courses)';
$string['check_courserole_notyet'] = 'Used only default course role.';
$string['check_courserole_ok'] = 'Default course role definitions is OK.';
$string['check_courserole_risky'] = 'Risky capabilities detected in <a href=\"$a\">context</a>.';
$string['check_defaultcourserole_anything'] = 'The \"doanything\" capability must not be allowed in this <a href=\"$a\">context</a>.';
$string['check_defaultcourserole_details'] = '<p>The default student role for course enrolment specifies the default role for courses. Please make sure no risky capabilities are allowed in this role.</p>
<p>The only supported legacy type for default role is <em>Student</em>.</p>';
$string['check_defaultcourserole_error'] = 'Incorrectly defined default course role \"$a\" detected!';
$string['check_defaultcourserole_legacy'] = 'Unsupported legacy type detected.';
$string['check_defaultcourserole_name'] = 'Default course role (global)';
$string['check_defaultcourserole_notset'] = 'Default role is not set.';
$string['check_defaultcourserole_ok'] = 'Site default role definition is OK.';
$string['check_defaultcourserole_risky'] = 'Risky capabilities detected in <a href=\"$a\">context</a>.';
$string['check_defaultuserrole_details'] = '<p>All logged in users are given capabilities of the default user role. Please make sure no risky capabilities are allowed in this role.</p>
<p>The only supported legacy type for the default user role is <em>Authenticated user</em>. The course view capability must not be enabled.</p>';
$string['check_defaultuserrole_error'] = 'The default user role \"$a\" is incorrectly defined!';
$string['check_defaultuserrole_name'] = 'Registered user role';
$string['check_defaultuserrole_notset'] = 'Default role is not set.';
$string['check_defaultuserrole_ok'] = 'Registered user role definition is OK.';
$string['check_displayerrors_details'] = '<p>Enabling the PHP setting <code>display_errors</code> is not recommended on production sites because error messages can reveal sensitive information about your server.</p>';
$string['check_displayerrors_error'] = 'The PHP setting to display errors is enabled. It is recommended that this is disabled.';
$string['check_displayerrors_name'] = 'Displaying of PHP errors';
$string['check_displayerrors_ok'] = 'Displaying of PHP errors disabled.';
$string['check_emailchangeconfirmation_details'] = '<p>It is recommended that an email confirmation step is required when users change their email address in their profile. If disabled, spammers may try to exploit the server to send spam.</p>
<p>Email field may be also locked from authentication plugins, this possibility is not considered here.</p>';
$string['check_emailchangeconfirmation_error'] = 'Users may enter any email address.';
$string['check_emailchangeconfirmation_info'] = 'Users may enter email addresses from allowed domains only.';
$string['check_emailchangeconfirmation_name'] = 'Email change confirmation';
$string['check_emailchangeconfirmation_ok'] = 'Confirmation of change of email address in user profile.';
$string['check_embed_details'] = '<p>Unlimited object embedding is very dangerous - any registered user may launch an XSS attack against other server users. This setting should be disabled on production servers.</p>';
$string['check_embed_error'] = 'Unlimited object embedding enabled - this is very dangerous for the majority of servers.';
$string['check_embed_name'] = 'Allow EMBED and OBJECT';
$string['check_embed_ok'] = 'Unlimited object embedding is not allowed.';
$string['check_frontpagerole_details'] = '<p>The default frontpage role is given to all registered users for frontpage activities. Please make sure no risky capabilities are allowed for this role.</p>
<p>It is recommended that a special role is created for this purpose and a legacy type role is not used.</p>';
$string['check_frontpagerole_error'] = 'Incorrectly defined frontpage role \"$a\" detected!';
$string['check_frontpagerole_name'] = 'Frontpage role';
$string['check_frontpagerole_notset'] = 'Frontpage role is not set.';
$string['check_frontpagerole_ok'] = 'Frontpage role definition is OK.';
$string['check_globals_details'] = '<p>Register globals is considered to be a highly insecure PHP setting.</p>
<p><code>register_globals=off</code> must be set in PHP configuration. This setting is controlled by editing your <code>php.ini</code>, Apache/IIS configuration or <code>.htaccess</code> file.</p>';
$string['check_globals_error'] = 'Register globals MUST be disabled. Please fix the server PHP settings immediately!';
$string['check_globals_name'] = 'Register globals';
$string['check_globals_ok'] = 'Register globals are disabled.';
$string['check_google_details'] = '<p>The Open to Google setting enables search engines to enter courses with guest access. There is no point in enabling this setting if guest login is not allowed.</p>';
$string['check_google_error'] = 'Search engine access is allowed but guest access is disabled.';
$string['check_google_info'] = 'Search engines may enter as guests.';
$string['check_google_name'] = 'Open to Google';
$string['check_google_ok'] = 'Search engine access is not enabled.';
$string['check_guestrole_details'] = '<p>The guest role is used for guests, not logged in users and temporary guest course access. Please make sure no risky capabilities are allowed in this role.</p>
<p>The only supported legacy type for guest role is <em>Guest</em>.</p>';
$string['check_guestrole_error'] = 'The guest role \"$a\" is incorrectly defined!';
$string['check_guestrole_name'] = 'Guest role';
$string['check_guestrole_notset'] = 'Guest role is not set.';
$string['check_guestrole_ok'] = 'Guest role definition is OK.';
$string['check_mediafilterswf_details'] = '<p>Automatic swf embedding is very dangerous - any registered user may launch an XSS attack against other server users. Please disable it on production servers.</p>';
$string['check_mediafilterswf_error'] = 'Flash media filter is enabled - this is very dangerous for the majority of servers.';
$string['check_mediafilterswf_name'] = 'Enabled .swf media filter';
$string['check_mediafilterswf_ok'] = 'Flash media filter is not enabled.';
$string['check_noauth_details'] = '<p>The <em>No authentication</em> plugin is not intended for production sites. Please disable it unless this is a development test site.</p>';
$string['check_noauth_error'] = 'The No authentication plugin cannot be used on production sites.';
$string['check_noauth_name'] = 'No authentication';
$string['check_noauth_ok'] = 'No authentication plugin is disabled.';
$string['check_openprofiles_details'] = '<p>Open user profiles can be abused by spammers. It is recommended that either <code>Force users to login for profiles</code> or <code>Force users to login</code> are enabled.</p>';
$string['check_openprofiles_error'] = 'Anyone can may view user profiles without logging in.';
$string['check_openprofiles_name'] = 'Open user profiles';
$string['check_openprofiles_ok'] = 'Login is required before viewing user profiles.';
$string['check_passwordpolicy_details'] = '<p>It is recommended that a password policy is set, since password guessing is very often the easiest way to gain unauthorised access.
Do not make the requirements too strict though, as this can result in users not being able to remember their passwords and either forgetting them or writing them down.</p>';
$string['check_passwordpolicy_error'] = 'Password policy not set.';
$string['check_passwordpolicy_name'] = 'Password policy';
$string['check_passwordpolicy_ok'] = 'Password policy enabled.';
$string['check_riskadmin_detailsok'] = '<p>Please verify the following list of system administrators:</p>$a';
$string['check_riskadmin_detailswarning'] = '<p>Please verify the following list of system administrators:</p>$a->admins
<p>It is recommended to assign administrator role in system context only. Following users have unsupported admin role assignments:</p>$a->unsupported';
$string['check_riskadmin_name'] = 'Administrators';
$string['check_riskadmin_ok'] = 'Found $a server administrator(s).';
$string['check_riskadmin_warning'] = 'Found $a->admincount server administrators and $a->unsupcount unsupported admin role assignments.';
$string['check_riskxss_details'] = '<p>RISK_XSS denotes all dangerous capabilities that only trusted users may use.</p>
<p>Please verify the following list of users and make sure that you trust them completely on this server:</p><p>$a</p>';
$string['check_riskxss_name'] = 'XSS trusted users';
$string['check_riskxss_warning'] = 'RISK_XSS - found $a users that have to be trusted.';
$string['check_unsecuredataroot_details'] = '<p>The dataroot directory must not be accessible via web. The best way to make sure the directory is not accessible is to use a directory outside the public web directory.</p>
<p>If you move the directory, you need to update the <code>\$CFG->dataroot</code> setting in <code>config.php</code> accordingly.</p>';
$string['check_unsecuredataroot_error'] = 'Your dataroot directory <code>$a</code> is in the wrong location and is exposed to the web!';
$string['check_unsecuredataroot_name'] = 'Insecure dataroot';
$string['check_unsecuredataroot_ok'] = 'Dataroot directory must not be accessible via the web.';
$string['check_unsecuredataroot_warning'] = 'Your dataroot directory <code>$a</code> is in the wrong location and might be exposed to the web.';
?>
+39
View File
@@ -1959,6 +1959,45 @@ function sql_cast_char2int($fieldname, $text=false) {
return $sql;
}
/**
* Returns the SQL text to be used in order to perform one bitwise AND operation
* between 2 integers.
* @param integer int1 first integer in the operation
* @param integer int2 second integer in the operation
* @return string the piece of SQL code to be used in your statement.
*/
function sql_bitand($int1, $int2) {
global $CFG;
switch ($CFG->dbfamily) {
case 'oracle':
return 'bitand((' . $int1 . '), (' . $int2 . '))';
break;
default:
return '((' . $int1 . ') & (' . $int2 . '))';
}
}
/**
* Returns the SQL text to be used in order to perform one bitwise OR operation
* between 2 integers.
* @param integer int1 first integer in the operation
* @param integer int2 second integer in the operation
* @return string the piece of SQL code to be used in your statement.
*/
function sql_bitor($int1, $int2) {
global $CFG;
switch ($CFG->dbfamily) {
case 'oracle':
return '((' . $int1 . ') + (' . $int2 . ') - ' . sql_bitand($int1, $int2) . ')';
break;
default:
return '((' . $int1 . ') | (' . $int2 . '))';
}
}
/**
* Returns SQL to be used as a subselect to find the primary role of users.
* Geoff Cant <[email protected]> (the author) is very keen for this to
+12
View File
@@ -323,6 +323,18 @@ table.flexible .r1 {
background-color: green;
}
#admin-report-security-index .statuswarning {
background-color: #f0e000;
}
#admin-report-security-index .statusserious {
background-color: #f07000;
}
#admin-report-security-index .statuscritical {
background-color: #f00000;
}
#adminsettings fieldset {
background-color: #EEE;
border-color: #BBB;