Difference between revisions of "Security"

Jump to: navigation, search
m
Line 1: Line 1:
This page describes how security best practices for Moodle developers, and how to use the Moodle API to achieve the best security for your scripts.
+
This page describes how to write secure Moodle code that is not vulnerable to anything that evil people my try to throw at it.
  
 +
The page is organised around the common types of security vulnerability. For each one, it explains
 +
# what the danger is,
 +
# how Moodle is designed to avoid the problem,
 +
# what you need to do as a Moodle developer to keep your code secure, and
 +
# what you can do as an administrator, to make your Moodle more secure.
 +
The explanation of each vulnerability is on a separate page, linked to in the list below.
  
==General==
+
This page also summarises all the key guidelines.
  
# Always try to structure your code in classes and functions without using globals ... this will promote better checking and tracing of variables.
 
  
 +
==Common types of security vulnerability==
  
==Authentication==
+
* [[Security:Unauthenticated access|Unauthenticated access]]
 +
* [[Security:Unauthorised access|Unauthorised access]]
 +
* [[Security:Cross-site_request_forgery|Cross-site request forgery]] (XSRF)
 +
* Cross-site scripting (XSS)
 +
* SQL injection
 +
* Command-line injection
 +
* Data-loss
 +
* Confidential information leakage
 +
* Configuration information leakage
 +
* Session fixation
 +
* [[Security:Denial of service|Denial of service]]
 +
* [[Security:Brute-forcing login|Brute-forcing login]]
 +
* [[Security:Insecure configuration management|Insecure configuration management]]
 +
* [[Security:Buffer overruns, and other platform weaknesses|Buffer overruns, and other platform weaknesses]]
 +
* [[Security:Social engineering|Social engineering]]
  
# Each file should check that the user is authenticated correctly, using '''require_login()''' and '''has_capability()''' or '''require_capability()'''.
 
  
==Handling input==
+
==Summary of the guidelines==
  
# Do not rely on 'register_globals'. Every variable must be properly initialised in every code file. It must be obvious where the variable came from.
+
===Authenticate the user===
# Do not ever use $_GET, $_POST or $_REQUEST. Use the appropriate required_param() or optional_param() appropriate to your need.
 
# Do not use data from $_SERVER if you can avoid it. This has portability issues.  Instead, use Moodle functions to get what you want.
 
# Wherever possible group all your required_param(), optional_param() and other variables initialisation at the beginning of each file to make them easy to find.
 
# Initialise all arrays and objects, even if empty. $a = array() or $obj = new stdClass();.
 
# Use 'sesskey' mechanism to protect form handling routines from attack. Basic example of use: when form is generated, include <input type="hidden" name="sesskey" value="<?php echo sesskey(); ?>" />. When you process the form check with if (!confirm_sesskey()) { print_error('confirmsesskeybad');}.
 
# If you presenting a normal form and processing it, always use the [[lib/formslib.php|moodleforms library]] - it will take care of most details for you.
 
 
==Storing data==
 
  
# Try to always use the XMLDB library in Moodle for all database access.  Not only does this provide security but it ensures correct behaviour on different databases.
+
* With very few exceptions, every script should call '''require_login''' or '''require_course_login''' as near the start as possible.
# If you must write custom some SQL code, make very sure it is correct. In particular watch out for missing quotes around values to avoid possible SQL 'injection' exploits.
 
# Before Moodle 2.0, any data sourced from the database MUST have [[Developer:Slashes|addslashes()]] applied to it BEFORE it can be written back. A whole object of data can be processed at once with addslashes_object().
 
# In Moodle 2.0 and later the database layer has changed and you MUST NOT use addslashes() anywhere as this is now automated.  
 
  
==Output==
 
  
#'''All texts should be printed using the format_text() function''', especially those that have come from users. This ensures that text is filtered and cleaned correctly. More information can be found on the page about [[Output_functions|output functions]].
+
===Check permissions===
  
==Logging==
+
* Before allowing the user to see anything or do anything, call to '''has_capability''' or '''require_capability'''.
 +
* If appropriate, restrict what people can see according to '''groups'''.
  
# User actions should be logged using the [[Logs|add_to_log()]] function. These logs are used for [[Settings#Show_activity_reports|activity reports]] and [[Logs]].
 
  
==Shell commands==
+
===Don't trust any input from users===
# Avoid them!  However, if you must use shell_exec() (or any other shell invoking function), make sure you clean parameters first with escapeshellcmd()/escapeshellarg (to prevent shell injection attacks).
 
  
==Error handling==
+
* Use '''[[lib/formslib.php|moodleforms]]''' whenever possible.
 +
* Before performing actions, use '''is_post_with_sesskey''' to check sesskey and that you are handling a POST request.
 +
** In Moodle 1.9, use '''data_submitted() && confirm_sesskey()''' instead.
 +
* Before destroying large amounts of data, add a confirmation step.
 +
* If not using a moodleform, clean input using '''optional_param''' or '''required_param''' with an appropriate '''PARAM_...''' type.
 +
** Do not access $_GET, $_POST or $_REQUEST directly.
 +
** Group optional_param and required_param calls together at the top of the script, to make them easy to find.
  
[[Category:Security]][[Category:Security]]
+
Similarly, clean data from other external resources like RSS feeds before use.
 +
 
 +
 
 +
===Clean and escape data before output===
 +
 
 +
* Use '''s''' or '''p''' to output plain text content.
 +
* use '''format_string''' to output content with minimal HTML like multi-lang spans (for example, course and activity names).
 +
* Use '''format_text''' to output all other content.
 +
** Only use $options->noclean if it requires a capability with RISK_XSS to input that content (for example web page resources).
 +
* Before Moodle 2.0, input from optional_param or required_param must have [[Developer:Slashes|'''stripslashes''' or '''stripslashes_recursive''']] applied if it is being output directly, rather than being stored in the database.
 +
 
 +
See [[Output functions]] for more details.
 +
 
 +
 
 +
===Escape data before storing it in the database===
 +
 
 +
* Use the XMLDB library. This takes care of most escaping issues for you.
 +
* When you must use custom SQL code, '''use place-holders''' to insert values into the queries.
 +
** Before Moodle 2.0, you have to build SQL be concatenating strings. Take particular care, especially with quoting values, to avoid SQL injection vulnerabilities.
 +
* Before Moodle 2.0, data loaded from the database must have [[Developer:Slashes|'''addslashes''' or '''addslashes_object''']] applied to it before it can be written back to the database. (addslashes should no longer be use anywhere in Moodle 2.0 code.)
 +
 
 +
 
 +
===Escape data before using it in shell commands===
 +
 
 +
* Avoid shell commands if at all possible.
 +
** Look to see if there is a PHP library instead.
 +
* If you can't avoid shell commands, use '''escapeshellcmd''' and '''escapeshellarg'''.
 +
 
 +
 
 +
===Log every request===
 +
 
 +
* Every script should call '''add_to_log'''.
 +
 
 +
 
 +
===Other good practice===
 +
 
 +
... that helps with security.
 +
 
 +
* Structure your code nicely, minimising the use of global variables. This makes the flow of data, and hence security, easier to verify.
 +
* Initialise objects ($x = new stdClass;) and arrays ($x = array()) before you first use them.
 +
* Test every input field with tricky input to ensure that it is escaped and un-escaped the right number of times everywhere, and that Unicode characters are not corrupted. My standard test input is:
 +
<nowiki>< > & &amp;lt; &amp;gt; &amp;amp; ' \' 碁 \ \\</nowiki>
 +
 
 +
 
 +
==See also==
 +
 
 +
* [[Coding]]
 +
 
 +
{{CategoryDeveloper}}
 +
[[Category:Security]]

Revision as of 15:07, 6 November 2009

This page describes how to write secure Moodle code that is not vulnerable to anything that evil people my try to throw at it.

The page is organised around the common types of security vulnerability. For each one, it explains

  1. what the danger is,
  2. how Moodle is designed to avoid the problem,
  3. what you need to do as a Moodle developer to keep your code secure, and
  4. what you can do as an administrator, to make your Moodle more secure.

The explanation of each vulnerability is on a separate page, linked to in the list below.

This page also summarises all the key guidelines.


Common types of security vulnerability


Summary of the guidelines

Authenticate the user

  • With very few exceptions, every script should call require_login or require_course_login as near the start as possible.


Check permissions

  • Before allowing the user to see anything or do anything, call to has_capability or require_capability.
  • If appropriate, restrict what people can see according to groups.


Don't trust any input from users

  • Use moodleforms whenever possible.
  • Before performing actions, use is_post_with_sesskey to check sesskey and that you are handling a POST request.
    • In Moodle 1.9, use data_submitted() && confirm_sesskey() instead.
  • Before destroying large amounts of data, add a confirmation step.
  • If not using a moodleform, clean input using optional_param or required_param with an appropriate PARAM_... type.
    • Do not access $_GET, $_POST or $_REQUEST directly.
    • Group optional_param and required_param calls together at the top of the script, to make them easy to find.

Similarly, clean data from other external resources like RSS feeds before use.


Clean and escape data before output

  • Use s or p to output plain text content.
  • use format_string to output content with minimal HTML like multi-lang spans (for example, course and activity names).
  • Use format_text to output all other content.
    • Only use $options->noclean if it requires a capability with RISK_XSS to input that content (for example web page resources).
  • Before Moodle 2.0, input from optional_param or required_param must have stripslashes or stripslashes_recursive applied if it is being output directly, rather than being stored in the database.

See Output functions for more details.


Escape data before storing it in the database

  • Use the XMLDB library. This takes care of most escaping issues for you.
  • When you must use custom SQL code, use place-holders to insert values into the queries.
    • Before Moodle 2.0, you have to build SQL be concatenating strings. Take particular care, especially with quoting values, to avoid SQL injection vulnerabilities.
  • Before Moodle 2.0, data loaded from the database must have addslashes or addslashes_object applied to it before it can be written back to the database. (addslashes should no longer be use anywhere in Moodle 2.0 code.)


Escape data before using it in shell commands

  • Avoid shell commands if at all possible.
    • Look to see if there is a PHP library instead.
  • If you can't avoid shell commands, use escapeshellcmd and escapeshellarg.


Log every request

  • Every script should call add_to_log.


Other good practice

... that helps with security.

  • Structure your code nicely, minimising the use of global variables. This makes the flow of data, and hence security, easier to verify.
  • Initialise objects ($x = new stdClass;) and arrays ($x = array()) before you first use them.
  • Test every input field with tricky input to ensure that it is escaped and un-escaped the right number of times everywhere, and that Unicode characters are not corrupted. My standard test input is:
< > & &lt; &gt; &amp; ' \' 碁 \ \\


See also

Template:CategoryDeveloper