hapijs / crumb

CSRF crumb generation and validation for hapi
Other
171 stars 50 forks source link

Generate function never called when Vision route has CORS enabled #90

Closed stongo closed 8 years ago

stongo commented 8 years ago

So I think found the reason why the crumb cookie isn't being set sometimes.

If you setup your server with CORS enabled globally but also using Vision like this:

const server = new Hapi.Server({
    connections: {
      routes: {
        cors: true
      }
    }
});
server.connection();
server.register([{
    register: require('vision'),
    options: Config.vision
}, {
    register: require('crumb'),
    options: Config.crumb
}])
...

And then proceed to create a few routes returning views, the view routes will never call Crumb's generate function, because https://github.com/hapijs/crumb/blob/master/lib/index.js#L83 will always fail unless CORS is explicitly turned off for the view route. The reason being that request.route.settings.cors evaluates to true, but then no CORS headers are actually set with the view, so the origin header isn't set making request.info.cors.isOriginMatch fail here https://github.com/hapijs/hapi/blob/ed195fad213a9da0f0762271c4907f4218e2abaf/lib/cors.js#L177-L179

As far as I can see, it comes down to the user being aware that a view route can't have CORS enabled. @hueniverse do you think there's any way to work around this in code, or will the best solution be to document the heck out of it in Crumb?

hueniverse commented 8 years ago

I'm not following the flow. Why are vision routes acting differently?

stongo commented 8 years ago

sorry @hueniverse you're right, it's not limited to vision routes, but to any route being access directly from browser when CORS is enabled.

so if CORS is set globally and one tries to access a route directly in browser for example, request.info.cors.isOriginMatch is always going to be false because the origin header isn't there.

this makes it so that a route can't be used in both CORS and non-CORS contexts when using crumb. maybe this is okay though, and I just need to clearly state that in crumb readme?

hueniverse commented 8 years ago

Directly you mean CURL?

stongo commented 8 years ago

CURL or in a browser

Here's the headers from chrome dev tools from a Vision route with CORS enabled

Request URL:http://localhost:8001/
Request Method:GET
Status Code:200 OK
Remote Address:127.0.0.1:8001

Response Headers
cache-control:no-cache
Connection:keep-alive
content-encoding:gzip
content-type:text/html; charset=utf-8
Date:Tue, 09 Aug 2016 18:02:02 GMT
Transfer-Encoding:chunked
vary:origin,accept-encoding

Request Headers
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Host:localhost:8001
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36

vs

curl -vv -H "origin: http://localhost" 127.0.0.1:8001
* Rebuilt URL to: 127.0.0.1:8001/
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8001 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1:8001
> User-Agent: curl/7.43.0
> Accept: */*
> origin: http://localhost
>
< HTTP/1.1 200 OK
< vary: origin
< access-control-allow-origin: http://localhost
< access-control-expose-headers: WWW-Authenticate,Server-Authorization
< set-cookie: crumb=xxxxxxxxxxxxxxxxxxxxxxxx; HttpOnly; Path=/
< cache-control: no-cache
< content-type: text/html; charset=utf-8
< content-length: 1638
< accept-ranges: bytes
< Date: Tue, 09 Aug 2016 17:38:16 GMT
< Connection: keep-alive
<
stongo commented 8 years ago

If I disable CORS for the same route, then crumb generate is called and crumb works as expected.

This came up when I was debugging someone's setup where the crumb cookie wasn't being set or added to the view context, and it was because CORS was enabled globally

hueniverse commented 8 years ago

Why isn't the browser sending the CORS headers?

stongo commented 8 years ago

I don't know honestly. Probably the root issue. I'll dig in to that

stongo commented 8 years ago

@hueniverse the browser will never use CORS for a single api request or for an initial html page as served by a Vision route for example. "A resource makes a cross-origin HTTP request when it requests a resource from a different domain than the one which the first resource itself serves" - https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS So that explains a route not being able to qualify a valid CORS request vs a same-origin request, as currently implemented. I'm wondering if the lack of a origin header is enough to confirm it's a same-origin request in the context of crumb, but need to dig in to the implications of that a bit more.

stongo commented 8 years ago

this page outlines when the header origin is served https://wiki.mozilla.org/Security/Origin

hueniverse commented 8 years ago

I think that's the right change. Enforce CORS where Origin is present.

stongo commented 8 years ago

Closed by https://github.com/hapijs/crumb/commit/a11b3586dc659be9515632096b05a607bd6f9acc

lock[bot] commented 4 years ago

This thread has been automatically locked due to inactivity. Please open a new issue for related bugs or questions following the new issue template instructions.