├── .gitattributes
├── LICENSE.md
├── README.md
├── composer.json
└── src
├── CsrfTokenToHeaders.php
└── CsrfTokenToView.php
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Aurélien Millet
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Slim 3 CSRF middleware utilities
2 |
3 | Requires [Slim 3 CSRF component](https://github.com/slimphp/Slim-Csrf)
4 |
5 | Basically, this package passes CSRF token to view (currently, official Slim Twig and PHP renderers are supported) or in response headers (for AJAX calls).
6 |
7 | ## Installation
8 |
9 | Requires [Composer](https://getcomposer.org/doc/00-intro.md)
10 |
11 | ```sh
12 | composer require aurmil/slim3-csrf-utilities
13 | ```
14 |
15 | Then require Composer autoload file
16 |
17 | ```php
18 | require 'vendor/autoload.php';
19 | ```
20 |
21 | ## Usage
22 |
23 | For an action that needs to display CSRF token in a view, add __Aurmil\Slim\CsrfTokenToView__ middleware before __Slim\Csrf\Guard__.
24 |
25 | For an AJAX called action that needs to return new token to the caller in response headers, add __Aurmil\Slim\CsrfTokenToHeaders__ middleware before __Slim\Csrf\Guard__.
26 |
27 | Let's consider a really light Slim app:
28 |
29 | index.php
30 |
31 | ```php
32 | getContainer();
46 |
47 | // If a route needs a view renderer
48 | $container['renderer'] = function ($c) {
49 | return new \Slim\Views\Twig(__DIR__, ['cache' => false]); // Twig
50 | return new \Slim\Views\PhpRenderer(__DIR__.'/'); // Or PHP
51 | };
52 |
53 | // CSRF component
54 | $container['csrf'] = function ($c) {
55 | return new \Slim\Csrf\Guard;
56 | };
57 |
58 | // HTML form including fields for CSRF token
59 | $app->get('/', function ($request, $response) {
60 | return $this->renderer->render($response, 'view.twig'); // Twig
61 | return $this->renderer->render($response, 'view.php'); // Or PHP
62 | })->add(new CsrfTokenToView($container->csrf, $container->renderer))
63 | ->add($container->csrf);
64 |
65 | // CSRF protected action, can be called by AJAX
66 | $app->post('/submit', function ($request, $response) {
67 | if ($request->isXhr()) {
68 | return $response->withJson(['success' => true]);
69 | } else {
70 | return $response->withRedirect('/');
71 | }
72 | })->add(new CsrfTokenToHeaders($container->csrf))
73 | ->add($container->csrf);
74 |
75 | // Slim dispatching
76 | $app->run();
77 | ```
78 |
79 | Twig view
80 |
81 | ```twig
82 |
83 |
84 |
85 |
86 | CSRF
87 |
88 |
89 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | ```
105 |
106 | Or PHP view
107 |
108 | ```php
109 |
110 |
111 |
112 |
113 | CSRF
114 |
115 |
116 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | ```
132 |
133 | JS file (fox AJAX calls) using jQuery
134 |
135 | ```js
136 | $(function () {
137 | var form = $('form');
138 | form.on('submit', function () {
139 | $.ajax({
140 | url: form.attr('action'),
141 | method: form.attr('method'),
142 | data: form.serialize(),
143 | cache: false,
144 | dataType: 'json',
145 | success: function (data) {
146 | console.log('OK');
147 | },
148 | error: function () {
149 | console.log('error')
150 | },
151 | complete: function (jqXHR) {
152 | var csrfToken = jqXHR.getResponseHeader('X-CSRF-Token');
153 |
154 | if (csrfToken) {
155 | try {
156 | csrfToken = $.parseJSON(csrfToken);
157 | var csrfTokenKeys = Object.keys(csrfToken);
158 | var hiddenFields = form.find('input.csrf[type="hidden"]');
159 |
160 | if (csrfTokenKeys.length === hiddenFields.length) {
161 | hiddenFields.each(function(i) {
162 | $(this).attr('name', csrfTokenKeys[i]);
163 | $(this).val(csrfToken[csrfTokenKeys[i]]);
164 | });
165 | }
166 | } catch (e) {
167 |
168 | }
169 | }
170 | }
171 | });
172 |
173 | return false;
174 | });
175 | });
176 | ```
177 |
178 | And .htaccess
179 |
180 | ```apache_conf
181 |
182 | RewriteEngine On
183 | RewriteCond %{REQUEST_FILENAME} !-f
184 | RewriteRule ^ index.php [QSA,L]
185 |
186 | ```
187 |
188 | ## License
189 |
190 | The MIT License (MIT). Please see [License File](https://github.com/aurmil/slim3-csrf-utilities/blob/master/LICENSE.md) for more information.
191 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aurmil/slim3-csrf-utilities",
3 | "description": "Slim Framework 3 CSRF protection middleware utilities",
4 | "keywords": ["slimphp", "slim", "framework", "middleware", "csrf"],
5 | "authors": [
6 | {
7 | "name": "Aurélien Millet",
8 | "homepage": "http://www.aurelien-millet.fr/",
9 | "role": "Developer"
10 | }
11 | ],
12 | "homepage": "https://github.com/aurmil/slim3-csrf-utilities",
13 | "type": "library",
14 | "license": "MIT",
15 | "require": {
16 | "php": ">=5.5.0",
17 | "slim/csrf": "^0.8"
18 | },
19 | "require-dev": {
20 | "slim/slim": "^3.3",
21 | "slim/php-view": "^2.1",
22 | "slim/twig-view": "^2.1"
23 | },
24 | "autoload": {
25 | "psr-4": {
26 | "Aurmil\\Slim\\": "src/"
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/CsrfTokenToHeaders.php:
--------------------------------------------------------------------------------
1 | csrf = $csrf;
29 | }
30 |
31 | /**
32 | * @param Request $request
33 | * @param Response $response
34 | * @param callable $next
35 | * @return Response
36 | */
37 | public function __invoke(Request $request, Response $response, callable $next)
38 | {
39 | $nameKey = $this->csrf->getTokenNameKey();
40 | $valueKey = $this->csrf->getTokenValueKey();
41 | $csrfToken = [
42 | $nameKey => $request->getAttribute($nameKey),
43 | $valueKey => $request->getAttribute($valueKey)
44 | ];
45 |
46 | if ($csrfToken[$nameKey] && $csrfToken[$valueKey]) {
47 | $response = $response->withHeader('X-CSRF-Token', json_encode($csrfToken));
48 | }
49 |
50 | return $next($request, $response);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/CsrfTokenToView.php:
--------------------------------------------------------------------------------
1 | csrf = $csrf;
34 | $this->renderer = $renderer;
35 | }
36 |
37 | /**
38 | * @param Request $request
39 | * @param Response $response
40 | * @param callable $next
41 | * @return Response
42 | * @throws UnexpectedValueException
43 | */
44 | public function __invoke(Request $request, Response $response, callable $next)
45 | {
46 | $nameKey = $this->csrf->getTokenNameKey();
47 | $valueKey = $this->csrf->getTokenValueKey();
48 | $csrfToken = [
49 | $nameKey => $request->getAttribute($nameKey),
50 | $valueKey => $request->getAttribute($valueKey)
51 | ];
52 |
53 | if ($csrfToken[$nameKey] && $csrfToken[$valueKey]) {
54 | // waiting for a possible Slim View Interface
55 | if ($this->renderer instanceof ArrayAccess) {
56 | $this->renderer['csrf_token'] = $csrfToken;
57 | } elseif (method_exists($this->renderer, 'addAttribute')) {
58 | $this->renderer->addAttribute('csrf_token', $csrfToken);
59 | } else {
60 | throw new UnexpectedValueException('Unsupported view renderer type.');
61 | }
62 | }
63 |
64 | return $next($request, $response);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------