Permalink
Browse files

add more about CSRF

  • Loading branch information...
1 parent b75d371 commit dca74b601478b6a236c89d21203a5d3dae97382d @pmjones pmjones committed Mar 18, 2013
View
105 README.md
@@ -227,27 +227,114 @@ class ContactForm extends Form
Now when we instantiate the `ContactForm` the inputs and filters will be there
automatically.
-Passing Options Into Forms
---------------------------
-
-TBD.
Applying CSRF Protections
-------------------------
-TBD.
+Aura.Input comes with an interface for implementations that prevent
+[cross-site request forgery](https://www.owasp.org/index.php/Cross-Site_Request_Forgery)
+attacks. To make use of this interface, you will need to provide your own
+CSRF implentation; this is because it depends on two things that Aura.Input
+cannot provide: an object that tells us if the user is authenticated or not,
+and an object to generate and retain a crytpographically secure random value
+for the CSRF token value. A psuedo-implementation follows.
+
+```php
+<?php
+namespace Vendor\Package\Input;
+
+use Aura\Input\AntiCsrfInterface;
+use Aura\Input\Fieldset;
+use Vendor\Package\CsrfObject;
+use Vendor\Package\UserObject;
+
+class AntiCsrf implements AntiCsrfInterface
+{
+ // a user object indicating if the user is authenticated or not
+ protected $user;
+
+ // a csrf value generation object
+ protected $csrf;
+
+ public function __construct(UserObject $user, CsrfObject $csrf)
+ {
+ $this->user = $user;
+ $this->csrf = $csrf;
+ }
+
+ // implementation of setField(); adds a CSRF token field to the fieldset.
+ public function setField(Fieldset $fieldset)
+ {
+ if (! $this->user->isAuthenticated()) {
+ // user is not authenticated so CSRF cannot occur
+ return;
+ }
+
+ // user is authenticated, so add a CSRF token
+ $fieldset->setField('__csrf_token', $this->csrf->getValue());
+ }
+
+ // implementation of isValid(). return true if CSRF token is present
+ // and of the correct value,
+ public function isValid(array $data)
+ {
+ if (! $this->user->isAuthenticated()) {
+ // user is not authenticated so CSRF cannot occur
+ return true;
+ }
+
+ // user is authenticated, so check to see if input has a CSRF token
+ // of the correct value
+ return isset($data['__csrf_token'])
+ && $data['__csrf_token'] == $this->csrf->getValue();
+ }
+}
+
+You can then pass an instance of your implementation into your form using the
+`setAntiCsrf()` method.
+
+```php
+<?php
+use Aura\Input\Form;
+use Aura\Input\Builder;
+use Aura\Input\Filter;
+use Vendor\Package\Input\AntiCsrf;
+use Vendor\Package\UserObject;
+use Vendor\Package\CsrfObject;
+
+$form = new Form(new Builder, new Filter);
+
+$anti_csrf = new AntiCsrf(new UserObject, new CsrfObject);
+$form->setAntiCsrf($anti_csrf);
+```
+
+Calling `setAntiCsrf()` adds a CSRF field to the form.
+
+When you call `fill()` on the form, it will check the CSRF value in the data
+to make sure it is correct. If not, the form will not fill in the data, and
+throw an exception and will not fill in the data.
+
Providing "Hints" To The View Layer
-----------------------------------
TBD.
-Reusable Fieldsets (aka "Sub-Forms")
-------------------------------------
+
+Passing Options Into Forms
+--------------------------
+
+TBD.
+
+
+Creating Reusable Fieldsets
+---------------------------
TBD.
-Fieldset Collections
---------------------
+
+Using Fieldset Collections
+--------------------------
TBD.
+
View
@@ -1,10 +1,10 @@
<?php
require_once __DIR__ . '/src/Aura/Input/AbstractInput.php';
+require_once __DIR__ . '/src/Aura/Input/AntiCsrfInterface.php';
require_once __DIR__ . '/src/Aura/Input/BuilderInterface.php';
require_once __DIR__ . '/src/Aura/Input/Builder.php';
require_once __DIR__ . '/src/Aura/Input/Collection.php';
require_once __DIR__ . '/src/Aura/Input/CollectionIterator.php';
-require_once __DIR__ . '/src/Aura/Input/CsrfInterface.php';
require_once __DIR__ . '/src/Aura/Input/Exception.php';
require_once __DIR__ . '/src/Aura/Input/Exception/CsrfViolation.php';
require_once __DIR__ . '/src/Aura/Input/Exception/NoSuchInput.php';
@@ -1,7 +1,7 @@
<?php
namespace Aura\Input;
-interface CsrfInterface
+interface AntiCsrfInterface
{
public function setField(Fieldset $fieldset);
public function isValid(array $data);
View
@@ -3,17 +3,17 @@
class Form extends Fieldset
{
- protected $csrf;
+ protected $anti_csrf;
- public function setCsrf(CsrfInterface $csrf)
+ public function setAntiCsrf(AntiCsrfInterface $anti_csrf)
{
- $this->csrf = $csrf;
- $this->csrf->setField($this);
+ $this->anti_csrf = $anti_csrf;
+ $this->anti_csrf->setField($this);
}
- public function getCsrf()
+ public function getAntiCsrf()
{
- return $this->csrf;
+ return $this->anti_csrf;
}
/**
@@ -27,7 +27,7 @@ public function getCsrf()
*/
public function fill(array $data)
{
- if ($this->csrf && ! $this->csrf->isValid($data)) {
+ if ($this->anti_csrf && ! $this->anti_csrf->isValid($data)) {
throw new Exception\CsrfViolation;
}
parent::fill($data);
@@ -15,9 +15,9 @@ public function testAddCsrf()
$this->assertSame($expect, $actual);
// set CSRF into the form
- $csrf = new MockCsrf;
- $form->setCsrf($csrf);
- $this->assertSame($csrf, $form->getCsrf());
+ $csrf = new MockAntiCsrf;
+ $form->setAntiCsrf($csrf);
+ $this->assertSame($csrf, $form->getAntiCsrf());
// there should be two fields now
$expect = ['foo', '__csrf_token'];
@@ -32,8 +32,8 @@ public function testMissingCsrf()
$form->setField('foo');
// set CSRF into the form
- $csrf = new MockCsrf;
- $form->setCsrf($csrf);
+ $csrf = new MockAntiCsrf;
+ $form->setAntiCsrf($csrf);
// load it with a missing csrf token
$data = ['foo' => 'bar'];
@@ -48,8 +48,8 @@ public function testBadCsrf()
$form->setField('foo');
// set CSRF into the form
- $csrf = new MockCsrf;
- $form->setCsrf($csrf);
+ $csrf = new MockAntiCsrf;
+ $form->setAntiCsrf($csrf);
// load it with a bad token
$data = ['foo' => 'bar', '__csrf_token' => 'badvalue'];
@@ -64,8 +64,8 @@ public function testGoodCsrf()
$form->setField('foo');
// set CSRF into the form
- $csrf = new MockCsrf;
- $form->setCsrf($csrf);
+ $csrf = new MockAntiCsrf;
+ $form->setAntiCsrf($csrf);
// load it with a good token
$data = ['foo' => 'bar', '__csrf_token' => 'goodvalue'];
@@ -1,7 +1,7 @@
<?php
namespace Aura\Input;
-class MockCsrf implements CsrfInterface
+class MockAntiCsrf implements AntiCsrfInterface
{
protected $value = 'goodvalue';

0 comments on commit dca74b6

Please sign in to comment.