Reputation: 10720
I am working with a Slim 3 project and I installed the CSRF package ("slim/csrf": "^0.8.2",)
In order to make POSTs request I am using postman. When sending the action I get the following error:
Failed CSRF check!
Here are my API routes (in this case, focus on the POST route):
<?php
/* RESTful endpoints or routes */
use App\Controllers\api\users\UserController;
$app->group('/api',function () use ($app){
$app->group('/users', function () {
$this->get('', UserController::class.':index');
$this->get('/{id}', UserController::class.':show');
$this->post('', UserController::class.':store');
});
});
Here is the controller supposed to get the info from the POST request where I get the error:
//Save a user via API
public function store($request,$response,$args)
{
//todo: validation!
var_dump($request->getParams());//todo: CSRF check failed!
die();
}
Here is where I registered the CSRF component:
//Register the CSRF Component
$container['csrf'] = function ($container){
return new \Slim\Csrf\Guard();
};
I tried this solution: https://stackoverflow.com/a/48266488/1883256 but it didn't work.
Is there any workaround to make it work? How do I prevent the CSRF to run on my API routes?
* Solved *
As Zamrony P. Juhara suggested, I decided to apply CSRF to the web routes except for the APIs routes.
Grouping all my web routes:
$app->group('',function ()use($app,$container){
/* ******* H O M E ********** */
require __DIR__ . '/web/home/home.php';
/* ********** T O P I C s ********** */
require __DIR__ . '/web/topics/topics.php';
/* ********** C O N T A C T *********** */
require __DIR__ . '/web/contact/contact.php';
/* And so on and etcetera ....*/
/* ********************************************************************************* */
})->add($container->get('csrf'));//Adding CSRF protection only for web routes
And, for example, inside the topics.php
routes file I have:
$app->group('/topics',function(){
$this->get('',TopicController::class.':index');
$this->get('/{id}',TopicController::class.':show')->setName('topics.show');
});
And as for the API routes, they stay the same.
Finally, inside my container I commented the following:
//$app->add($container->get('csrf')); //I've commented this line in order to add CSRF for specific routes (all except APIs ones)
Upvotes: 0
Views: 1712
Reputation: 5262
You need to make sure that you add Slim\Csrf\Guard
middleware to route or application (if you want to apply csrf for all routes). For example
To apply csrf middleware to all routes
$csrf = $container->csrf;
$app->add($csrf);
or to apply for certain routes only
$csrf = $container->csrf;
$app->group('/api',function () use ($app, $csrf){
$app->group('/users', function () {
$this->get('', UserController::class.':index')
->add($csrf);
$this->get('/{id}', UserController::class.':show');
$this->post('', UserController::class.':store')
->add($csrf);
});
});
You also need to make sure that there are Csrf token name/value data passed with request. When you use Postman, you need to find a way to obtain token name key/value pair before execute POST.
Following code is excerpt from Slim Csrf Readme.
// CSRF token name and value
$nameKey = $this->csrf->getTokenNameKey();
$valueKey = $this->csrf->getTokenValueKey();
$name = $request->getAttribute($nameKey);
$value = $request->getAttribute($valueKey);
// Render HTML form which POSTs to /bar with two hidden input fields for the
// name and value:
// <input type="hidden" name="<?= $nameKey ?>" value="<?= $name ?>">
// <input type="hidden" name="<?= $valueKey ?>" value="<?= $value ?>">
Read Slim Csrf Readme for more information.
Upvotes: 1