Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Bug 583095 - Add CSRF Control to Plugin Edit/Create Forms

  • Loading branch information...
commit ae6af7ca85329b04142a242e92d0b44ad10968e1 1 parent 7bc2327
@lmorchard authored
View
19 application/controllers/local.php
@@ -25,11 +25,28 @@ public function __construct()
}
/**
+ * In reaction to an invalid CSRF crumb, throw up a generic error view.
+ */
+ public function invalidcrumb()
+ {
+ header('HTTP/1.1 400 Bad Request', true, 400);
+ $this->view->set_filename('invalidcrumb');
+ $this->render();
+
+ cef_logging::log(
+ cef_logging::ACCESS_CONTROL_VIOLATION,
+ 'Access Control Violation', 5
+ );
+
+ exit();
+ }
+
+ /**
* In reaction to a 403 Forbidden event, throw up a forbidden view.
*/
public function show_forbidden()
{
- header('403 Forbidden');
+ header('HTTP/1.1 403 Forbidden', true, 403);
$this->view->set_filename('forbidden');
$this->render();
View
22 application/controllers/plugins.php
@@ -14,6 +14,28 @@ class Plugins_Controller extends Local_Controller {
public function __construct()
{
parent::__construct();
+
+ // Protect some methods by requiring an anti-CSRF crumb on POST.
+ $crumb_methods = array(
+ 'create', 'edit', 'detail', 'copy', 'deploy', 'delete',
+ 'requestpush', 'addtrusted', 'removetrusted'
+ );
+ if (in_array(Router::$method, $crumb_methods)) {
+
+ // Generate a crumb for these methods.
+ $this->view->crumb = csrf_crumbs::generate();
+
+ // Require a valid crumb on POST requests.
+ if ('post' == request::method()) {
+ // TODO: Disable this if/when details becomes an external API
+ $crumb = $this->input->server('HTTP_X_CSRF_CRUMB', null);
+ if (empty($crumb)) $crumb = $this->input->post('crumb');
+ if (!csrf_crumbs::validate($crumb)) {
+ Router::$method = 'invalidcrumb';
+ }
+ }
+
+ }
}
/**
View
1  application/views/plugins/addtrusted.html
@@ -13,6 +13,7 @@
<h2>{{plugin.name | e}}</h2>
<form action="" method="POST">
+ <input type="hidden" name="crumb" value="{{ crumb }}" />
<p>{% blocktrans %}Make {{ screen_name_e }} trusted for "{{plugin_name_e}}"{% endblocktrans %}</p>
<div>
<input type="submit" value="{% trans "Add as trusted" %}" />
View
1  application/views/plugins/copy.html
@@ -8,6 +8,7 @@
{% block content %}
<form action="" method="POST">
+ <input type="hidden" name="crumb" value="{{ crumb }}" />
<p>{% trans "Copy this plugin to your sandbox?" %}</p>
<div>
<input type="submit" value="{% trans "Copy to Sandbox" %}" />
View
2  application/views/plugins/create.html
@@ -20,8 +20,10 @@
{% else %}
<form class="contribute" action="" method="post">
+
{% set data, errors as form_data, form_errors %}
+ {{ forms.hidden(data, errors, 'crumb', crumb) }}
{{ forms.hidden(data, errors, 'detected_version', _GET.version) }}
{{ forms.fieldset('New plugin details', 'plugin_details') }}
View
1  application/views/plugins/delete.html
@@ -10,6 +10,7 @@
<h2>{{plugin.name | e}}</h2>
<form action="" method="POST">
+ <input type="hidden" name="crumb" value="{{ crumb }}" />
<p>{% trans "Delete this plugin?" %}</p>
<div>
<input type="submit" value="{% trans "Delete plugin" %}" />
View
1  application/views/plugins/deploy.html
@@ -8,6 +8,7 @@
{% block content %}
<form action="" method="POST">
+ <input type="hidden" name="crumb" value="{{ crumb }}" />
<p>{% trans "Push changes to this plugin live?" %}</p>
<div>
<input type="submit" value="{% trans "Push plugin changes live" %}" />
View
2  application/views/plugins/edit.html
@@ -22,6 +22,7 @@
"{{base_url}}plugins/detail/{{plugin.pfs_id|e}}.json";
{% endif %}
PluginDir.Editor.plugin_properties = {{ properties | json }};
+ PluginDir.Editor.csrf_crumb = "{{ crumb }}";
{% endblock %}
{% block content %}
@@ -32,6 +33,7 @@
{% endif %}
<form id="editor">
+ <input type="hidden" name="crumb" value="{{ crumb }}" />
<fieldset>
<legend>{% trans "Options" %}</legend>
View
1  application/views/plugins/removetrusted.html
@@ -13,6 +13,7 @@
<h2>{{plugin.name | e}}</h2>
<form action="" method="POST">
+ <input type="hidden" name="crumb" value="{{ crumb }}" />
<p>{% blocktrans %}Remove {{ screen_name_e }} as trusted for "{{plugin_name_e}}"{% endblocktrans %}</p>
<div>
<input type="submit" value="{% trans "Remove as trusted" %}" />
View
1  application/views/plugins/requestpush.html
@@ -8,6 +8,7 @@
{% block content %}
<form action="" method="POST">
+ <input type="hidden" name="crumb" value="{{ crumb }}" />
<p>{% trans "Request approval for changes?" %}</p>
<div>
<input type="submit" value="{% trans "Request approval" %}" />
View
5 htdocs/js/PluginDir/Editor.js
@@ -11,6 +11,8 @@ PluginDir.Editor = (function () {
json_url: null,
// Description of plugin properties.
plugin_properties: {},
+ // Anti-CSRF crumb provided by server
+ csrf_crumb: null,
// Whether or not to autosave using idle timer.
autosave: false,
// Idle timer used to save when user is inbetween edits.
@@ -183,6 +185,9 @@ PluginDir.Editor = (function () {
// Perform the actual save via POST.
$.ajax({
type: 'POST',
+ beforeSend: function (req) {
+ req.setRequestHeader('X-CSRF-Crumb', $this.csrf_crumb);
+ },
url: url,
contentType: 'application/json',
data: json,
Please sign in to comment.
Something went wrong with that request. Please try again.