6

I'm trying to get a header value with:

Request::header('csrf_token')

though, my firebug says in the headers that I have the csrf_token set to baMDpF0yrfRerkdihFack1Sa9cchUk8qBzm0hK0C. In fact, I can get that csrf_token instead with a native php code:

getallheaders()['csrf_token']

Now the question is am I doing my XSRF-protection right? or maybe there is a flaw in that php code I did, that I really have to use buggy laravel 4 function

Request::header('csrf_token')

which returns nothing but blank. And I just missed something. maybe in my Laravel 4 configurations, etc?

P.S: I am using AngularJS, but maybe it does not matter what clientside I use. I have this link as my guide: How to send csrf_token() inside AngularJS form using Laravel API?

Community
  • 1
  • 1
Tyro Hunter
  • 755
  • 1
  • 8
  • 20
  • Allow me a little question back: Why do you expect that `Request::header('csrf_token')` returns that header value in the first place? Just because of the name of the class-method? Have you looked into the source of that method what it actually does? – hakre Sep 03 '13 at 06:17
  • @hakre: thanks for that comment and idea. Source code you say? hmm I dont find it easy and intuitive to follow. So what must be the appropriate function to use then? if not Request::header(); like how Content-type was retrieve in laravel four's documentation; Request::header('Content-Type'); – Tyro Hunter Sep 03 '13 at 06:31
  • I just wanted to find out about why you have choosen that code. As your comment shows, some kind of minimal understanding seems missing which is an off-topic criteria for this Q&A website as you don't even expect the code in question to work and reproduce the issue. I suggest you ask around in the Laravel 4 forums instead. – hakre Sep 03 '13 at 06:32
  • Questions concerning problems with code you've written must **describe the specific problem** — and **include valid code to reproduce it** — in the question itself. See [SSCCE.org](http://sscce.org/) for guidance. – hakre Sep 03 '13 at 06:33
  • alright, ill see it then. Thank you – Tyro Hunter Sep 03 '13 at 06:39

5 Answers5

9

I solved the problem by removing the underscore '_' in csrf_token so it would be crsftoken instead.

Request::header('csrf_token'); // Not working

Request::header('csrftoken'); // Working!
Luís Cruz
  • 14,780
  • 16
  • 68
  • 100
RSorensen
  • 141
  • 2
  • 4
2

I think the problem there is that in the following answer at How to send csrf_token() inside AngularJS form using Laravel that you used, the csrf_token is not sent in the header of your XMLHttpRequest but in the form it self.

You need then to filter it in your laravel backend as a regular Input field. See below for a working example :

Route::filter('csrf_json', function()
{
    if (Session::token() != Input::get('csrf_token'))
    {
        throw new Illuminate\Session\TokenMismatchException;
    }
});

UPDATE

If you want to use headers in Angular, you would rather write something like :

$httpProvider.defaults.headers.common['Authorization'] = TOKEN;

In order to aplly a new header to your XMLHttpRequests. Then it is easily catchable even with raw php such as :

$aHeaders = getallheaders();
if (Session::token() != $aHeaders['authorization']) etc.
Community
  • 1
  • 1
lightalex
  • 879
  • 1
  • 11
  • 26
2

Problem

Laravel is removing headers with an underscore in the name when retrieving them with the Request::header() method. Additionally, all header names are converted to lower case in the Request::header() method.

Short Solution

On the frontend, replace all underscores in header names with dashes. csrf_token becomes csrf-token

Long Solution

Add the Laravel CSRF token as an Angular constant on your main page / layout.

<script>
    angular.module("myApp").constant("CSRF_TOKEN", "<?php echo csrf_token(); ?>"); 
</script>

Add the token as a default header for all your requests in Angular.

angular.module("myApp").run(function($http, CSRF_TOKEN){
    $http.defaults.headers.common["csrf-token"] = CSRF_TOKEN;
})

Have your csrf filter in Laravel check for a match in the headers rather than an input.

/**
 * Check that our session token matches the CSRF request header token.
 *
 * @return json
 */
Route::filter("csrf", function() {
    if (Session::token() !== Request::header("csrf-token")) {
        return Response::json(array(
            "error" => array(
                "code"    => "403",
                "message" => "Ah ah ah, you didn't say the magic word.",
            ),
        ));
    }
}
John G
  • 41
  • 4
1

Request::header() is indeed used for the retrieval of headers, but check where the token is being set.. the CSRF token should be placed into the session by Laravel, and then it can be accessed through the Session::token() method.

If you look at the HTML generated through calls to the Form:: class, you'll see a hidden element called _token, which should then be compared to the token in the session. You can access that using Input::get('_token'), as with any other incoming GET or POST variable.

...However, all this shouldn't really be necessary, as it can be managed easily through the pre-defined CSRF filter in filters.php, just add that filter to the desired route or route group and you'll be protected, without having to get into the details of it.

msturdy
  • 10,479
  • 11
  • 41
  • 52
  • Hello. I cannot use the Form:: class of laravel since my forms are generated by Angularjs as my frontend. But that's not a problem. In my SPA i was able to get that token by `` so I used that value in my frontend to make a header csrf_token which will then be read and matched to Session::token() (which does fine) by laravel4, though I can get that by getallheaders()['csrf_token']; I was just wondering why Request::header('csrf_token') returns empty – Tyro Hunter Sep 04 '13 at 04:30
  • ah, apologies, missed that part! I think Hakre was right, best to take up on the laravel forums! :) – msturdy Sep 04 '13 at 10:54
0

the problem is with the Symfony Request object, which is extended in the Laravel framework. See this github thread

https://github.com/laravel/framework/issues/1655#issuecomment-20595277

The solution in your case would be to set the header name to HTTP_CSRF_TOKEN or HTTP_X_CSRF_TOKEN if you like prefixing X to your custom http headers.