Moodle

use of portfolio callbackfile and callbackclass parameters in portfolio/add.php is unaccepable

Details

  • Type: Sub-task Sub-task
  • Status: Closed Closed
  • Priority: Blocker Blocker
  • Resolution: Fixed
  • Affects Version/s: 2.0
  • Fix Version/s: 2.0
  • Component/s: Portfolio API
  • Labels:
    None
  • Affected Branches:
    MOODLE_20_STABLE
  • Fixed Branches:
    MOODLE_20_STABLE

Description

Following code from portfolio/add.php is a security nightmare - allowing anybody (including guests) to include ANY moodle file from dirroot and instantiate ANY class with ANY parameters is unacceptable, please note that there is also no sesskey CSRF protection!

$callbackfile = optional_param('callbackfile', null, PARAM_PATH); // callback file eg /mod/forum/lib.php - the location of the exporting content
$callbackclass = optional_param('callbackclass', null, PARAM_ALPHAEXT); // callback class eg forum_portfolio_caller - the class to handle the exporting content.

$callbackargs = array();
foreach (array_keys(array_merge($_GET, $_POST)) as $key) {
if (strpos($key, 'ca_') === 0) {
if (!$value = optional_param($key, false, PARAM_ALPHAEXT)) {
if (!$value = optional_param($key, false, PARAM_NUMBER)) { $value = optional_param($key, false, PARAM_PATH); }
}
// strip off ca_ for niceness
$callbackargs[substr($key, 3)] = $value;
}
}
// righto, now we have the callback args set up
// load up the caller file and class and tell it to set up all the data
// it needs
require_once($CFG->dirroot . $callbackfile);
$caller = new $callbackclass($callbackargs);

Activity

Hide
Penny Leach added a comment -

Hi Petr,

Adding sesskey protection is trivial and a simple oversight, thank you for catching it. All the portfolio add buttons are handled through the portfolio_add_button's to_html method, so adding sesskey there and a check in portfolio/add.php will change all cases.

Regarding your other concern, do you have any better solution? I followed Martin's original spec for this, please see http://docs.moodle.org/en/index.php?title=Development:Portfolio_API&oldid=23088.

Also, it's not "ANY" class, those classes are all subclasses of portfolio_caller (this can easily be checked in portfolio/add.php).

Show
Penny Leach added a comment - Hi Petr, Adding sesskey protection is trivial and a simple oversight, thank you for catching it. All the portfolio add buttons are handled through the portfolio_add_button's to_html method, so adding sesskey there and a check in portfolio/add.php will change all cases. Regarding your other concern, do you have any better solution? I followed Martin's original spec for this, please see http://docs.moodle.org/en/index.php?title=Development:Portfolio_API&oldid=23088. Also, it's not "ANY" class, those classes are all subclasses of portfolio_caller (this can easily be checked in portfolio/add.php).
Hide
Petr Škoda (skodak) added a comment -

I suppose you can pass in something that can be easily verified - then derive class name and expected php file from it.

Show
Petr Škoda (skodak) added a comment - I suppose you can pass in something that can be easily verified - then derive class name and expected php file from it.
Hide
Penny Leach added a comment -

I don't think that the class name can be derived, as even now certain modules implement different portfolio_caller subclasses for different cases, see for example glossary, which behaves differently depending on whether it's a single entry or complete database export.

(grep for portfolio_module_caller)

The other option is to create a registry of all portfolio-exportable content but I dont think there's a good way to do it. This is not limited to activity modules, whole courses could be exportable.

There isn't an easy way to provide a mapping between portfolio exporters and their file/classes, other than:

1. Keep a database table of all classnames and files - I think this is a bit unmaintanable, as it's an additional "install time" question to ask modules/blocks/questiontypes/all plugins and we have it in code anyway

2. Everytime we draw the portfolio add icon on the screen, insert a possible export location into a database table. This is also not a good idea, because just because the icon gets drawn on the page doesn't mean that the user will ever click it , and it could result in multiple inserts per page load for a case that is never triggered.

I don't think the current situation is too terrible, if we have the following:

1. added sesskey protection as per my last comment, this is np to add
2. added check that the class to call is a subclass of portfolio_caller

Also bear in mind that the data that gets passed through as callback parameters to the constructor are pretty limited in regards to their datatype, it's limited to param_alphaext, param_number and param_path. That's pretty restrictive!

Show
Penny Leach added a comment - I don't think that the class name can be derived, as even now certain modules implement different portfolio_caller subclasses for different cases, see for example glossary, which behaves differently depending on whether it's a single entry or complete database export. (grep for portfolio_module_caller) The other option is to create a registry of all portfolio-exportable content but I dont think there's a good way to do it. This is not limited to activity modules, whole courses could be exportable. There isn't an easy way to provide a mapping between portfolio exporters and their file/classes, other than: 1. Keep a database table of all classnames and files - I think this is a bit unmaintanable, as it's an additional "install time" question to ask modules/blocks/questiontypes/all plugins and we have it in code anyway 2. Everytime we draw the portfolio add icon on the screen, insert a possible export location into a database table. This is also not a good idea, because just because the icon gets drawn on the page doesn't mean that the user will ever click it , and it could result in multiple inserts per page load for a case that is never triggered. I don't think the current situation is too terrible, if we have the following: 1. added sesskey protection as per my last comment, this is np to add 2. added check that the class to call is a subclass of portfolio_caller Also bear in mind that the data that gets passed through as callback parameters to the constructor are pretty limited in regards to their datatype, it's limited to param_alphaext, param_number and param_path. That's pretty restrictive!
Hide
Penny Leach added a comment -

Just committed 1 and 2 from above. Leaving open in case of any further discussion about the registry, but I think this is sufficient.

Show
Penny Leach added a comment - Just committed 1 and 2 from above. Leaving open in case of any further discussion about the registry, but I think this is sufficient.
Hide
Penny Leach added a comment -

Petr I think we should be closed now.

I added the class hierarchy check, and of course sesskey.

Show
Penny Leach added a comment - Petr I think we should be closed now. I added the class hierarchy check, and of course sesskey.

People

Vote (0)
Watch (1)

Dates

  • Created:
    Updated:
    Resolved: