The Security Component creates an easy way to integrate tighter security in your application. It provides methods for various tasks like:
Restricting which HTTP methods your application accepts.
Form tampering protection
Requiring that SSL be used.
Limiting cross controller communication.
Like all components it is configured through several configurable parameters.
All of these properties can be set directly or through setter methods of the
same name in your controller’s beforeFilter()
.
By using the Security Component you automatically get form tampering protection. Hidden token fields will automatically be inserted into forms and checked by the Security component.
If you are using Security component’s form protection features and
other components that process form data in their startup()
callbacks, be sure to place Security Component before those
components in your initialize()
method.
Note
When using the Security Component you must use the FormHelper to create
your forms. In addition, you must not override any of the fields’ “name”
attributes. The Security Component looks for certain indicators that are
created and managed by the FormHelper (especially those created in
create()
and
end()
). Dynamically altering
the fields that are submitted in a POST request (e.g. disabling, deleting
or creating new fields via JavaScript) is likely to cause the request to be
send to the blackhole callback.
You should always verify the HTTP method being used before executing to avoid
side-effects. You should check the HTTP method or
use Cake\Http\ServerRequest::allowMethod()
to ensure the correct
HTTP method is used.
If an action is restricted by the Security Component it is
‘black-holed’ as an invalid request which will result in a 400 error
by default. You can configure this behavior by setting the
blackHoleCallback
configuration option to a callback function
in the controller.
By configuring a callback method you can customize how the blackhole process works:
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Security->setConfig('blackHoleCallback', 'blackhole');
}
public function blackhole($type, SecurityException $exception)
{
if ($exception->getMessage() === 'Request is not SSL and the action is required to be secure') {
// Reword the exception message with a translatable string.
$exception->setMessage(__('Please access the requested page through HTTPS'));
}
// Re-throw the conditionally reworded exception.
throw $exception;
// Alternatively, handle the error, e.g. set a flash message &
// redirect to HTTPS version of the requested page.
}
Note
use $this->Security->config()
for CakePHP versions prior to 3.4
The $type
parameter can have the following values:
‘auth’ Indicates a form validation error, or a controller/action mismatch error.
‘secure’ Indicates an SSL method restriction failure.
New in version cakephp/cakephp: 3.2.6
As of v3.2.6 an additional parameter is included in the blackHole callback,
an instance of the Cake\Controller\Exception\SecurityException
is
included as a second parameter.
Sets the actions that require a SSL-secured request. Takes any number of arguments. Can be called with no arguments to force all actions to require a SSL-secured.
Sets the actions that require a valid Security Component generated token. Takes any number of arguments. Can be called with no arguments to force all actions to require a valid authentication.
A list of controllers which can send requests to this controller. This can be used to control cross controller requests.
A list of actions which are allowed to send requests to this controller’s actions. This can be used to control cross controller requests.
These configuration options allow you to restrict cross controller
communication. Set them with the setConfig()
method, or
config()
if you are using a CakePHP version below 3.4.
By default the SecurityComponent
prevents users from tampering with forms in
specific ways. The SecurityComponent
will prevent the following things:
Unknown fields cannot be added to the form.
Fields cannot be removed from the form.
Values in hidden inputs cannot be modified.
Preventing these types of tampering is accomplished by working with the FormHelper
and tracking which fields are in a form. The values for hidden fields are
tracked as well. All of this data is combined and turned into a hash. When
a form is submitted, the SecurityComponent
will use the POST data to build the same
structure and compare the hash.
Note
The SecurityComponent will not prevent select options from being added/changed. Nor will it prevent radio options from being added/changed.
Set to a list of form fields to exclude from POST validation. Fields can be
unlocked either in the Component, or with
FormHelper::unlockField()
. Fields that have been unlocked are
not required to be part of the POST and hidden unlocked fields do not have
their values checked.
Set to false
to completely skip the validation of POST
requests, essentially turning off form validation.
The above configuration options can be set with setConfig()
or
config()
for CakePHP versions below 3.4.
Using the security component is generally done in the controller’s
beforeFilter()
. You would specify the security restrictions you
want and the Security Component will enforce them on its startup:
namespace App\Controller;
use App\Controller\AppController;
use Cake\Event\Event;
class WidgetsController extends AppController
{
public function initialize()
{
parent::initialize();
$this->loadComponent('Security');
}
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
if ($this->request->getParam('admin')) {
$this->Security->requireSecure();
}
}
}
The above example would force all actions that had admin routing to require secure SSL requests:
namespace App\Controller;
use App\Controller\AppController;
use Cake\Event\Event;
class WidgetsController extends AppController
{
public function initialize()
{
parent::initialize();
$this->loadComponent('Security', ['blackHoleCallback' => 'forceSSL']);
}
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
if ($this->request->getParam('admin')) {
$this->Security->requireSecure();
}
}
public function forceSSL($error = '', SecurityException $exception = null)
{
if ($exception instanceof SecurityException && $exception->getType() === 'secure') {
return $this->redirect('https://' . env('SERVER_NAME') . Router::url($this->request->getRequestTarget()));
}
throw $exception;
}
}
Note
Use $this->request->here()
for CakePHP versions prior to 3.4.0
This example would force all actions that had admin routing to require secure
SSL requests. When the request is black holed, it will call the nominated
forceSSL()
callback which will redirect non-secure requests to secure
requests automatically.
CSRF or Cross Site Request Forgery is a common vulnerability in web applications. It allows an attacker to capture and replay a previous request, and sometimes submit data requests using image tags or resources on other domains. To enable CSRF protection features use the Cross Site Request Forgery.
There may be cases where you want to disable all security checks for an action
(ex. AJAX requests). You may “unlock” these actions by listing them in
$this->Security->unlockedActions
in your beforeFilter()
. The
unlockedActions
property will not affect other features of
SecurityComponent
:
namespace App\Controller;
use App\Controller\AppController;
use Cake\Event\Event;
class WidgetController extends AppController
{
public function initialize()
{
parent::initialize();
$this->loadComponent('Security');
}
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Security->setConfig('unlockedActions', ['edit']);
}
}
Note
Use $this->Security->config()
for CakePHP versions prior to 3.4.0
This example would disable all security checks for the edit action.