Skip to content

Commit

Permalink
Merge pull request #86 from gsteel/v2/csrf-validator
Browse files Browse the repository at this point in the history
Add the CSRF validator from `laminas-validator`
  • Loading branch information
gsteel authored Jun 19, 2024
2 parents 984f78d + 98fa057 commit b8cd890
Show file tree
Hide file tree
Showing 8 changed files with 712 additions and 15 deletions.
5 changes: 5 additions & 0 deletions docs/book/installation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# This Is Only a Placeholder

The content of this page can be found under:

https://github.com/laminas/documentation-theme/blob/master/theme/pages/installation.html
44 changes: 44 additions & 0 deletions docs/book/validators/csrf.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# CSRF Validator

`Laminas\Session\Validator\Csrf` provides the ability to both generate and validate CSRF tokens.
This allows you to validate if a form submission originated from the same site, by confirming the value of the CSRF field in the submitted form is the same as the one contained in the original form.

[Cross-Site Request Forgery (CSRF)](https://en.wikipedia.org/wiki/Cross-site_request_forgery) is a security vector in which an unauthorized request is accepted by a server on behalf of another user; it is essentially an exploit of the trust a site places on a user's browser.

The typical mitigation is to create a one-time token that is transmitted as part of the original form, and which must then be transmitted back by the client.
This token expires after first submission or after a short amount of time, preventing replays or further submissions.
If the token provided does not match what was originally sent, an error should be returned.

## Supported Options

The following options are supported for `Laminas\Session\Validator\Csrf`.

| Option | Description | Optional/Mandatory |
|-----------|---------------------------------------------------------------------------------|--------------------|
| `name` | The name of the CSRF element | Optional |
| `salt` | The salt for the CSRF token | Optional |
| `session` | The session container instance that will store the CSRF tokens between requests | **Mandatory** |
| `timeout` | The [TTL](https://en.wikipedia.org/wiki/Time_to_live) for the CSRF token | Optional |

## Basic Usage

Here is a basic example.

```php
// Initialise a new session container
// or use the existing one in your application
$session = new Laminas\Session\Container();

// Create the validator
$validator = new Laminas\Validator\Csrf([
'session' => $session,
]);
$hash = $validator->getHash();

// ...Render the hash in the form.

// Validate the hash after form submission.
echo ($validator->isValid($hash))
? "Token is valid"
: "Token is NOT valid";
```
4 changes: 4 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ nav:
- Introduction: validators/introduction.md
- "Http User Agent": validators/httpuseragent.md
- "Remote Address": validators/remoteaddr.md
- "CSRF Validator": validators/csrf.md
- "Writing Custom Validators": validators/writing-custom-validators.md
- "Application Integration":
- "Usage in a laminas-mvc application": application-integration/usage-in-a-laminas-mvc-application.md
Expand All @@ -19,6 +20,9 @@ site_description: 'Object-oriented interface to PHP sessions and storage.'
repo_url: 'https://github.com/laminas/laminas-session'
extra:
project: Components
installation:
config_provider_class: 'Laminas\Session\ConfigProvider'
module_class: 'Laminas\Session\Module'
plugins:
- redirects:
redirect_maps:
Expand Down
16 changes: 8 additions & 8 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -382,14 +382,6 @@
<code><![CDATA[(string) $name]]></code>
</RedundantCastGivenDocblockType>
</file>
<file src="src/ConfigProvider.php">
<UndefinedClass>
<code><![CDATA[ConfigInterface]]></code>
<code><![CDATA[StorageInterface]]></code>
<code><![CDATA[\Zend\Session\ManagerInterface]]></code>
<code><![CDATA[\Zend\Session\SessionManager]]></code>
</UndefinedClass>
</file>
<file src="src/Container.php">
<MethodSignatureMustProvideReturnType>
<code><![CDATA[offsetGet]]></code>
Expand Down Expand Up @@ -1494,6 +1486,14 @@
<code><![CDATA[$maxlifetime]]></code>
</ParamNameMismatch>
</file>
<file src="test/Validator/CsrfTest.php">
<DocblockTypeContradiction>
<code><![CDATA[$container->hash]]></code>
</DocblockTypeContradiction>
<TypeDoesNotContainType>
<code><![CDATA[assertIsString]]></code>
</TypeDoesNotContainType>
</file>
<file src="test/Validator/RemoteAddrTest.php">
<MissingConstructor>
<code><![CDATA[$backup]]></code>
Expand Down
29 changes: 22 additions & 7 deletions src/ConfigProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

namespace Laminas\Session;

use Zend\Session\Config\ConfigInterface;
use Zend\Session\Storage\StorageInterface;
use Laminas\ServiceManager\Factory\InvokableFactory;
use Laminas\ServiceManager\ServiceManager;

/** @psalm-import-type ServiceManagerConfiguration from ServiceManager */
class ConfigProvider
{
/**
Expand All @@ -16,13 +17,14 @@ public function __invoke()
{
return [
'dependencies' => $this->getDependencyConfig(),
'validators' => $this->getValidatorConfig(),
];
}

/**
* Retrieve dependency config for laminas-session.
*
* @return array
* @return ServiceManagerConfiguration
*/
public function getDependencyConfig()
{
Expand All @@ -34,10 +36,10 @@ public function getDependencyConfig()
SessionManager::class => ManagerInterface::class,

// Legacy Zend Framework aliases
\Zend\Session\SessionManager::class => SessionManager::class,
ConfigInterface::class => Config\ConfigInterface::class,
\Zend\Session\ManagerInterface::class => ManagerInterface::class,
StorageInterface::class => Storage\StorageInterface::class,
'Zend\Session\SessionManager' => SessionManager::class,
'Zend\Session\Config\ConfigInterface' => Config\ConfigInterface::class,
'Zend\Session\ManagerInterface' => ManagerInterface::class,
'Zend\Session\Storage\StorageInterface' => Storage\StorageInterface::class,
],
'factories' => [
Config\ConfigInterface::class => Service\SessionConfigFactory::class,
Expand All @@ -46,4 +48,17 @@ public function getDependencyConfig()
],
];
}

/** @return ServiceManagerConfiguration */
public function getValidatorConfig(): array
{
return [
'factories' => [
Validator\Csrf::class => InvokableFactory::class,
],
'aliases' => [
'csrf' => Validator\Csrf::class,
],
];
}
}
1 change: 1 addition & 0 deletions src/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public function getConfig()
$provider = new ConfigProvider();
return [
'service_manager' => $provider->getDependencyConfig(),
'validators' => $provider->getValidatorConfig(),
];
}
}
Loading

0 comments on commit b8cd890

Please sign in to comment.