0

I created an app using Slim 2 a while ago and I'm trying to add Angular. It's been going well so far, but I can no longer use the CSRF protection that I was using since Angular is handling all my post requests. Below is the Before Middleware I had working.

<?php

namespace Cache\Middleware;

use Exception;
use Slim\Middleware;

class CsrfMiddleware extends Middleware {
protected $key;

public function call() {

    $this->key = $this->app->config->get('csrf.key');

    $this->app->hook('slim.before', [$this, 'check']);

    $this->next->call();
}

public function check() {
    if (!isset($_SESSION[$this->key])) {
        $_SESSION[$this->key] = $this->app->hash->hash($this->app->randomlib->generateString(128));
    }

    $token = $_SESSION[$this->key];

    if (in_array($this->app->request()->getMethod(), ['POST', 'PUT', 'DELETE'])) {
        $submittedToken = $this->app->request()->post($this->key) ?: '';

        if (!$this->app->hash->hashCheck($token, $submittedToken)) {
            throw new Exception('CSRF token mismatch');
        }
    }

    $this->app->view()->appendData([
        'csrf_key' => $this->key,
        'csrf_token' => $token
    ]);
}

}

I know that angular automatically looks for a token named XSRF-TOKEN and adds it to the header as X-XSRF-TOKEN. How can I modify the middleware below to write, read, and compare the correct values.

EDIT:

After looking at this again and checking the slim documentation, I changed the line:

$submittedToken = $this->app->request()->post($this->key) ?: '';

to this:

$submittedToken = $this->app->request->headers->get('X-XSRF-TOKEN') ?: '';

If I'm right, this assigns the $submittedToken the value passed as X-XSRF-TOKEN in the header. It's throwing the exception with the message from the middleware "CSRF token mismatch". This feels like progress. Below is the relevant Angular:

app.controller('itemsCtrl', ['$scope', '$http', function($scope, $http) {

    // Initailize object when the page first loads
    $scope.getAll = function() {
        $http.post('/domain.com/admin/getNames').success(function(data) {
            $scope.names = data;
        });
    }

EDIT

Below is where the php code stands now. I think this is working. I've received the expected CSRF error when I remove the cookie or alter the value of the $token before submitting a form. I'm a little concerned about what will happen when I have multiple users on. I haven't tested it yet. Based on this revision, does the protection appear sound?

<?php

namespace Cache\Middleware;

use Exception;
use Slim\Middleware;

class CsrfMiddleware extends Middleware {
protected $key;

public function call() {

    $this->key = $this->app->config->get('csrf.key');

    $this->app->hook('slim.before', [$this, 'check']);

    $this->next->call();
}

public function check() {
    // if (!isset($_SESSION[$this->key])) {
    if (!isset($_SESSION[$this->key])) {
        // $_SESSION[$this->key] = $this->app->hash->hash($this->app->randomlib->generateString(128));
        $this->app->setcookie($this->key, $this->app->hash->hash($this->app->randomlib->generateString(128)));
    }

    // $token = $_SESSION[$this->key];
    if(isset($_COOKIE[$this->key])) {
        $token = $_COOKIE[$this->key];
    }

    if (in_array($this->app->request()->getMethod(), ['POST', 'PUT', 'DELETE'])) {
        // $submittedToken = $this->app->request()->post($this->key) ?: '';
        $submittedToken = $this->app->request->headers->get('X-XSRF-TOKEN') ?: '';

        if (!$this->app->hash->hashCheck($token, $submittedToken)) {
            throw new Exception('CSRF token mismatch');
        }
    }
}
}
user2530671
  • 428
  • 3
  • 13

1 Answers1

0

From the Angular docs for $http Cross Site Request Forgery (XSRF) Protection:

The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName properties of either $httpProvider.defaults at config-time, $http.defaults at run-time, or the per-request config object.

So to change them to use different cookie name / header name, change those values.

Chas Brown
  • 386
  • 1
  • 10
  • I've seen that implemented elsewhere. Right now, I've changed the csrf.key name to XSRF-TOKEN so that it will be picked up by Angular. Not sure how to test if that's working. Also not sure how to get the middleware to read the header name? – user2530671 Jan 09 '17 at 23:23