0

I've set up an hook to implement XSRF in laravel:

view

@section('content')
<div class="content" data-ui-view></div>
    <script type="text/javascript">
        window.user = <% $data['user'] %>; 
        document.cookie = "XSRF-TOKEN=<% $data['token'] %>";
    </script>
@stop

controller

$token = csrf_token();
$this->layout->content = View::make('home.content')->with('data', array('token'=> $token, 'user'=> json_encode($userData)));

filter

Route::filter('xsrf', function()
{
    if((!isset($_COOKIE['XSRF-TOKEN']) || is_null(Request::header('X-XSRF-TOKEN'))) || ($_COOKIE['XSRF-TOKEN'] !== Request::header('X-XSRF-TOKEN'))){
        return Response::make('Not Found', 404);
    }
});

Route::filter('xhr', function()
{
    if(!Request::ajax()){
        return Response::make('Not Found', 404);
    } 

});

route

Route::group(array('prefix' => 'api/v1', 'before' => 'xhr|xsrf'), function() {

    /* User */
    Route::post('user', array('as' => 'base.user.register', 'uses' => 'App\Controllers\UserController@register'));

 });

xhr test

public function testUser404() {

        $crawler = $this->client->request('GET', '/api/v1/user');

        $this->assertResponseStatus(404);
    }

How can I test base.user.register for xsrf filter ?

ENDED UP

protected function getCookieValue()
{
    $crawler = $this->client->request('GET', '/');
    $text = $crawler->filter('body > div > script')->eq(0)->text();
    $chunks1 = explode("\n", trim($text));
    $chunks2 = explode("=", trim($chunks1[1]));
    return rtrim($chunks2[2], ';"');
}

public function testUser401() {
    $_COOKIE['XSRF-TOKEN'] = $this->getCookieValue();
    $this->client->setServerParameter('HTTP_X-Requested-With', 'XMLHttpRequest');
    $this->client->setServerParameter('HTTP_X-XSRF-TOKEN', $_COOKIE['XSRF-TOKEN']);
    $crawler = $this->client->request('GET', '/api/v1/user');
    $this->assertResponseStatus(401);
}

it's a lot tricky (I'd love to hear some better ones :) ) but it seems to work

Whisher
  • 31,320
  • 32
  • 120
  • 201

1 Answers1

1

I don't think this is a particularly great idea (I'd love to hear some better ones), but this is what I've done for XSRF in tests:

protected function getToken() {
    $this->client->request('GET', 'http://localhost/admin/login');

    preg_match('/<input name="_token" type="hidden" value="([a-zA-Z0-9]+)">/', $this->client->getResponse()->getContent(), $matches);

    return $matches[1];
}

public function testAdminCanLogin() {
  $this->client->request('POST', '/admin/login', [
    'email'    => $this->email,
    'password' => $this->password,
    '_token'   => $this->getToken()
  ]);

  // A successful POST redirects you.
  $this->assertFalse($this->client->getResponse()->isOk());
  $this->assertTrue($this->client->getResponse()->isRedirect());
}

Essentially here the test does a prior request to get a valid token, then passes it back in the POST.

DanSingerman
  • 36,066
  • 13
  • 81
  • 92
  • thanks this is can be an idea but I need also set a cookie to make angularjs work take a look at Cross Site Request Forgery (XSRF) Protection https://docs.angularjs.org/api/ng/service/$http – Whisher Jul 15 '14 at 10:58
  • DanSingerman I've updated my question it seems to work how do you think about ? – Whisher Jul 16 '14 at 08:42
  • @Whisher - I don't think you should be setting your token only in a cookie. It needs to be in the form/page you are trying to protect request from. See http://stackoverflow.com/questions/4463422/csrf-can-i-use-a-cookie?rq=1 – DanSingerman Jul 16 '14 at 08:53
  • DanSingerman I'm using angularjs and the way to protect is set a cookie than check in the http header I don't mind of laravel csrf in this case – Whisher Jul 16 '14 at 09:23
  • DanSingerman I think also in your case you could exploit the $crawler instead of regex may be safer using dom instead of regex – Whisher Jul 16 '14 at 09:55