Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

HTTP header field name case-insensitivity is not being respected which leads to improper Session handling. #8278

Closed
davemo opened this Issue Jun 14, 2013 · 4 comments

Comments

Projects
None yet
4 participants

davemo commented Jun 14, 2013

Preface

I did file this on the Laravel repo, laravel/framework#1639 and was directed to report it here.

Overview

Symfony is incorrectly handling HTTP request header field names that are lowercase, which causes the Session handler to improperly issue a new session cookie on every request.

I encountered this bug when working with a NodeJS app configured to proxy requests to Laravel, which sits on top of Symfony. The HTTP spec is pretty clear that header field names are case-insensitive:

4.2 Message Headers

... Each header field consists
of a name followed by a colon (":") and the field value. Field names
are case-insensitive.
...

Reproducing the Bug

I've recorded a video of this bug in action, consider it the tl;dr :)

Here's the breakdown of how I tested this and my configuration that lead me to believe the problem exists in the way Symfony parses request headers:

  1. I have laravel configured to run php artisan serve --host=127.0.0.1 --port=3000
  2. I have node running on port 8000, using the npm module http-proxy to forward requests to port 3000

To rule out node and http-proxy as a potential source of problems, I first used netcat to listen on port 3000 (nc -l 3000) and capture requests that http-proxy was sending, here's a dump of what http-proxy is forwarding to Laravel (note the lower case header field-names):

davidmosher@localhost:~/code/temp/laravel 
$ nc -l 3000
GET /auth/csrf_token HTTP/1.1
host: localhost:8000
connection: keep-alive
cache-control: no-cache
pragma: no-cache
accept: application/json, text/javascript
x-requested-with: XMLHttpRequest
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36
content-type: application/x-www-form-urlencoded
referer: http://localhost:8000/
accept-encoding: gzip,deflate,sdch
accept-language: en-US,en;q=0.8
cookie: laravel_session=doh0284ujk57ebnldlm2plp795
x-forwarded-for: 127.0.0.1
x-forwarded-port: 53245
x-forwarded-proto: http

When I use telnet 127.0.0.1 3000 in another terminal session I paste the above request that has lowercase header field-names in and receive the following response from Laravel:

HTTP/1.1 200 OK
Connection: close
X-Powered-By: PHP/5.4.14
Set-Cookie: laravel_session=kicg6iu0aobufkl036itar6km6; expires=Thu, 13-Jun-2013 18:48:12 GMT; path=/; HttpOnly
Set-Cookie: laravel_session=kicg6iu0aobufkl036itar6km6; expires=Thu, 13-Jun-2013 18:48:12 GMT; path=/; httponly
Cache-Control: no-cache
Date: Thu, 13 Jun 2013 16:48:12 GMT
Content-Type: application/json

Note the double Set-Cookie and the laravel_session has a different value than what was sent in the request. If I modify the header keys in my request to uppercase all the words like so:

GET /auth/csrf_token HTTP/1.1
Host: localhost:8000
Connection: keep-alive
Cache-Control: no-cache
Pragma: no-cache
Accept: application/json, text/javascript
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://localhost:8000/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Cookie: laravel_session=doh0284ujk57ebnldlm2plp795
X-Forwarded-For: 127.0.0.1
X-Forwarded-Port: 53245
X-Forwarded-Proto: http

Then I get a correct response from Laravel, as follows:

HTTP/1.1 200 OK
Host: localhost:8000
Connection: close
X-Powered-By: PHP/5.4.14
Set-Cookie: laravel_session=doh0284ujk57ebnldlm2plp795; expires=Thu, 13-Jun-2013 18:49:40 GMT; path=/; httponly
Cache-Control: no-cache
Date: Thu, 13 Jun 2013 16:49:40 GMT
Content-Type: application/json

Conclusion

Having ruled out my proxy completely, using netcat and telnet I can only conclude that Laravel or Symfony is treating http request header field names differently depending on the casing; this causes major problems for anyone setting up a proxy that may use lower case request header field names to forward requests to laravel and expects Session management to work properly.

Is this something that should be fixed by Laravel or at a lower level in Symfony?

Howdy again!

On a fresh install of Laravel, I was able to reproduce this issue using PHP's built-in server on PHP 5.4.12.

I started up the PHP web server, and then used node-http-proxy to proxy to it.

$ php artisan server --host=172.16.27.134 --port 3000

Headers from PHP Server

screen shot 2013-06-14 at 3 24 24 pm

Note that the Set-Cookie header is creating a new Cookies/Session

Headers from Apache

On the same install, using Apache on Port 80, this issue did not present itself (again, using node-http-proxy):

screen shot 2013-06-14 at 3 18 59 pm

The Session remains persistent!

Conclusion:

Looks to me like it's PHP's internal server being weird with headers.

I encountered the same problem on another project, I reported the bug https://bugs.php.net/bug.php?id=65633 and it was promptly fixed php/php-src@3c3b2b5
remember to report upstream when you find a bug ;)

Member

stof commented Sep 10, 2013

Closing as it is not bug in Symfony and this has been fixed in PHP already

@stof stof closed this Sep 10, 2013

davemo commented Sep 10, 2013

@francescolaffi Thank you for filing this upstream, I did actually try and file it myself but hit a pretty big wall in the php.net bug reporting form that deterred me; if you have any ability to pass feedback onto the PHP team I think there would be more bug reports filed if that form wasn't so massive and unwieldly.

For my part, I'll "try harder" next time ;)

Thanks again for taking this on @francescolaffi!

@davemo davemo referenced this issue in davemo/frontend-workflows-with-grunt-and-angularjs Dec 31, 2013

Open

I am getting csrf_token mismatch error #4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment