'lithium\security\validation\RequestToken', 'formSignature' => 'lithium\security\validation\FormSignature' ]; protected $_state = []; /** * Constructor. Configures the helper with the default settings for interacting with * security tokens. * * @param array $config * @return void */ public function __construct(array $config = []) { $defaults = ['sessionKey' => 'security.token', 'salt' => null]; parent::__construct($config + $defaults); } /** * Generates a request key used to protect your forms against CSRF attacks. See the * `RequestToken` class for examples and proper usage. * * @see lithium\security\validation\RequestToken * @param array $options Options used as HTML when generating the field. * @return string Returns a hidden `` field containing a request-specific CSRF token * key. */ public function requestToken(array $options = []) { $defaults = ['name' => 'security.token', 'id' => false]; $options += $defaults; $requestToken = $this->_classes['requestToken']; $flags = array_intersect_key($this->_config, ['sessionKey' => '', 'salt' => '']); $value = $requestToken::key($flags); $name = $options['name']; unset($options['name']); return $this->_context->form->hidden($name, compact('value') + $options); } /** * 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. * ```php * use lithium\security\validation\FormSignature; * FormSignature::config(['secret' => 'a long secret key']); * ``` * * In the view call the `sign()` method before creating the form. * ```php * security->sign(); ?> * form->create(...); ?> * // Form fields... * form->end(); ?> * ``` * * In the corresponding controller action verify the signature. * ```php * 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_: If `true`, _locks_ the value specified in the field when the field * is generated, such that tampering with the value will invalidate the signature. Defaults * to `true` for hidden fields, and `false` for all other form inputs. * * - `'exclude'` _boolean_: If `true`, 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 to `false`. * * @see lithium\template\helper\Form * @see lithium\security\validation\FormSignature * @param object $form Optional. Allows specifying an instance of the `Form` helper manually. * @return void */ public function sign($form = null) { $form = $form ?: $this->_context->form; if (isset($state[spl_object_hash($form)])) { return; } Filters::apply($form, 'create', function($params, $next) use ($form) { $this->_state[spl_object_hash($form)] = [ 'fields' => [], 'locked' => [], 'excluded' => [] ]; return $next($params); }); Filters::apply($form, 'end', function($params, $next) use ($form) { $id = spl_object_hash($form); if (!$this->_state[$id]) { return $next($params); } $formSignature = $this->_classes['formSignature']; $value = $formSignature::key($this->_state[$id]); echo $form->hidden('security.signature', compact('value')); $this->_state[$id] = []; return $next($params); }); Filters::apply($form, '_defaults', function($params, $next) use ($form) { $defaults = [ 'locked' => ($params['method'] === 'hidden' && $params['name'] !== '_method'), 'exclude' => $params['name'] === '_method' ]; $options = $params['options']; $options += $defaults; $params['options'] = array_diff_key($options, $defaults); $result = $next($params); if ($params['method'] === 'label') { return $result; } $value = isset($params['options']['value']) ? $params['options']['value'] : ""; $type = [ $options['exclude'] => 'excluded', !$options['exclude'] => 'fields', $options['locked'] => 'locked' ]; if (!$name = preg_replace('/(\.\d+)+$/', '', $params['name'])) { return $result; } $this->_state[spl_object_hash($form)][$type[true]][$name] = $value; return $result; }); } } ?>