lithium\template\helper\Security::sign()
Binds the Security
helper to the Form
helper to create a signature used to secure form
fields against tampering.
First FormSignature
must be provided with a secret unique to your app. This is best
done in the bootstrap process. The secret key should be a random lengthy string.
use lithium\security\validation\FormSignature;
FormSignature::config(array('secret' => 'a long secret key'));
In the view call the sign()
method before creating the form.
<?php $this->security->sign(); ?>
<?=$this->form->create(...); ?>
// Form fields...
<?=$this->form->end(); ?>
In the corresponding controller action verify the signature.
if ($this->request->is('post') && !FormSignature::check($this->request)) {
// The key didn't match, meaning the request has been tampered with.
}
Calling this method before a form is created adds two additional options to the $options
parameter in all form inputs:
'locked'
boolean: Iftrue
, locks the value specified in the field when the field is generated, such that tampering with the value will invalidate the signature. Defaults totrue
for hidden fields, andfalse
for all other form inputs.'exclude'
boolean: Iftrue
, this field and all subfields of the same name will be excluded from the signature calculation. This is useful in situations where fields may be added dynamically on the client side. Defaults tofalse
.
Parameters
-
object
$form
Optional. Allows specifying an instance of the
Form
helper manually.
Returns
voidSource
public function sign($form = null) {
$state =& $this->_state;
$classes = $this->_classes;
$form = $form ?: $this->_context->form;
$id = spl_object_hash($form);
$hasBound = isset($state[$id]);
if ($hasBound) {
return;
}
$form->applyFilter('create', function($self, $params, $chain) use ($form, &$state) {
$id = spl_object_hash($form);
$state[$id] = array('fields' => array(), 'locked' => array(), 'excluded' => array());
return $chain->next($self, $params, $chain);
});
$form->applyFilter('end', function($self, $params, $chain) use ($form, &$state, $classes) {
$id = spl_object_hash($form);
if (!$state[$id]) {
return $chain->next($self, $params, $chain);
}
$value = $classes['formSignature']::key($state[$id]);
echo $form->hidden('security.signature', compact('value'));
$state[$id] = array();
return $chain->next($self, $params, $chain);
});
$form->applyFilter('_defaults', function($self, $params, $chain) use ($form, &$state) {
$defaults = array(
'locked' => ($params['method'] === 'hidden' && $params['name'] !== '_method'),
'exclude' => $params['name'] === '_method'
);
$options = $params['options'];
$options += $defaults;
$params['options'] = array_diff_key($options, $defaults);
$result = $chain->next($self, $params, $chain);
if ($params['method'] === 'label') {
return $result;
}
$value = isset($params['options']['value']) ? $params['options']['value'] : "";
$type = array(
$options['exclude'] => 'excluded',
!$options['exclude'] => 'fields',
$options['locked'] => 'locked'
);
if (!$name = preg_replace('/(\.\d+)+$/', '', $params['name'])) {
return $result;
}
$state[spl_object_hash($form)][$type[true]][$name] = $value;
return $result;
});
}