Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Security:Cross-site request forgery: Difference between revisions

From MoodleDocs
(2 intermediate revisions by 2 users not shown)
Line 44: Line 44:
==What you need to do in your code==
==What you need to do in your code==


''Note, some of the Moodle 2.0 ideas mentioned here are still under discussion. That is what you get for writing coding guidelines at the same time as you are having design discussions.''--[[User:Tim Hunt|Tim Hunt]] 10:48, 23 November 2009 (UTC)
Use the [[Form API]] whenever possible for handling HTML forms. This automatically checks the sesskey and request method for you.


* Use a [[lib/formslib.php|moodleform]] whenever possible for handling HTML forms. This automatically checks the sesskey and request method for you.
There are valid cases when using forms is not appropriate and you need to perform an action based on a parameter submitted via GET request - such as various action links. In this case, you have to manually include the sesskey among submitted parameters, and then make sure the submitted sesskey value is valid.
* Where you cannot use a moodleform, check that this is a POST request with a valid sesskey before your code lets the user make any significant changes.
 
** In Moodle 2.0, use the is_post_with_sesskey() function.
Include the sesskey among the submitted parameters:
** Before Moodle 2.0, user the data_submitted() function to test whether this is a post request, and either confirm_sesskey() or require_sesskey() to check the sesskey.
 
* When outputting user-interface to trigger actions, use buttons instead of links
<code php>
** In Moodle 2.0 that means $OUTPUT->button() specifying ->method = 'post', and include sesskey in the params.
$action = new moodle_url('/admin/tool/do/something.php', ['delete' => $id, 'sesskey' => sesskey()]);
** Before Moodle 2.0, use print_single_button(...) specifying $method = 'post', and including sesskey in $options.
echo html_writer::link($action, get_string('delete'));
* If you want the action triggered by an icon, rather than a button, use an simple form with <input type="image">, rather than an <img ...> in a link.
</code>
 
And in the target script, make sure to check the submitted sesskey is correct before executing the operation:
 
<code php>
$delete = optional_param('delete', null, PARAM_INT);
 
if ($delete) {
    require_sesskey();
    // Do whatever you need to, like $DB->delete_records(...) etc.
}
</code>
 
Note that when using standard elements like $OUTPUT->continue_button() and other elements based on the single_button widget submitted via POST method, the sesskey can be implicitly added to submitted parameters. Still, it is your duty to explicitly check the submitted value is valid.


==What you need to do as an administrator==
==What you need to do as an administrator==
Line 65: Line 78:
* [[Coding]]
* [[Coding]]


{{CategoryDeveloper}}
[[Category:Security]]
[[Category:Security]]

Revision as of 20:31, 18 August 2016

This page forms part of the Moodle security guidelines.


What is the danger?

When you put a web application on the internet, you are making it available so that anyone can send requests to it, and any request can be simply encoded as a URL.

Suppose that in Moodle, the way for an Administrator to delete a user was to click a Delete button in their user profile, and then click Yes on an confirmation page. Suppose that as a result of that, the Administrator's web browser sends a POST request to http://example.com/moodle/user/delete.php, with post data ?id=123&confirm=1.

Now suppose that Evil Hacker knows this, and wants to trick the administrator into deleting another user. (If Evil Hacker makes this request himself, he will see a permission denied error.)

All the Hacker Needs to do is to put the link http://example.com/moodle/user/delete.php?id=123&confirm=1 somewhere where the administrator will click on it. For example, they could send the Administrator an email with a link saying "Look at this cool YouTube video" but where the link actually goes to the delete URL. The Administrator may click on the link without checking where it goes, and when the Administrator clicks that link, user 123 really will be deleted.

Or, more seriously, the student could put a post in a forum that Administrators will read, and in the forum post, put an <img src="http://example.com/moodle/user/delete.php?id=123&confirm=1" />. That way, the moment the Administrator reads the forum, user 123 will be deleted.

It is also possible to fake POST requests, you can simple put the form on external site and post a link pointing to that site on your Moodle server, it is also possible to use external flash instead of forms.

It may be a bit surprising, but this type of attack may be used against servers behind firewall on private network. It is not important where is the exploiting code, you can attack any server users may access from their browsers.


How Moodle avoids this problem

Session key

The most important protection is the concept of a sesskey, short for session key.

When you log in, Moodle adds a random string to your session. Whever it prints a link or a button to perform a significant action, it adds the sesskey value to the submitted data. Before performing the action, it checks the sesskey value in the request with the one in the session, and the action is only performed if the two match.

Therefore, the request to delete a user is actually something like http://example.com/moodle/user/delete.php?id=123&confirm=1&sesskey=E8i5BCxLJR, and there is no way for Evil Hacker to know what the sesskey is, so they cannot construct an URL that tricks the admin into deleting a user.


Use HTTP correctly

Web applications use HTTP to encode requests from the user. In HTTP, there are various types of request. The two most important are GET and POST.

GET requests should be used for getting information. So, for example, viewing a user's profile should be a GET request.

POST requests should be used for changing things in the application. For example deleting a user should be a POST request.

When you click a link or load an image, it is always a GET request. When you submit a form, it is either a POST or a GET request, depending on the form.

Moodle should only process changes in response to a POST request. If that is the case, then it does Evil Hacker no good to trick a user into clicking on a link or viewing an embedded image. They have to trick a user into clicking a form submit button, which is harder.

What you need to do in your code

Use the Form API whenever possible for handling HTML forms. This automatically checks the sesskey and request method for you.

There are valid cases when using forms is not appropriate and you need to perform an action based on a parameter submitted via GET request - such as various action links. In this case, you have to manually include the sesskey among submitted parameters, and then make sure the submitted sesskey value is valid.

Include the sesskey among the submitted parameters:

$action = new moodle_url('/admin/tool/do/something.php', ['delete' => $id, 'sesskey' => sesskey()]); echo html_writer::link($action, get_string('delete'));

And in the target script, make sure to check the submitted sesskey is correct before executing the operation:

$delete = optional_param('delete', null, PARAM_INT);

if ($delete) {

   require_sesskey();
   // Do whatever you need to, like $DB->delete_records(...) etc.

}

Note that when using standard elements like $OUTPUT->continue_button() and other elements based on the single_button widget submitted via POST method, the sesskey can be implicitly added to submitted parameters. Still, it is your duty to explicitly check the submitted value is valid.

What you need to do as an administrator

  • This is really only a code issue, but try not to fall for Evil Hacker's tricks ;-).


See also