Hacker News new | past | comments | ask | show | jobs | submit login

No, but you can achieve a GET which is also a "safe request method" per RFC7231. All of these requests should be idempotent.

I'm not a fan of the hacks that exist to allow HTML forms to emulate other request methods. They're off by default in ASP.NET Core MVC, which is good IMO.




"should". Real apps are much more complicated than what they are in theory. In theory all CSRF protections must be based on an auth token, in practice they routinely rely on the method or referrer.

For this reason browser upgrades must be extremely careful to not break older protections.

That's why you cannot set your own referer (which is supposed to mean nothing), you cannot supply Content-type: application/json unless instructed by CORS preflight, etc etc.

Here, the backwards compatibility was clearly broken. It was never possible to send HEAD few years ago with regular XHR or <img>s. Web standards owe $25k back to github. Yes, github's routing was flawed but it wasn't exploitable until browsers allowed HEAD in fetch() no-cors mode.


>For this reason browser upgrades must be extremely careful to not break older protections.

It's too late for that though. We've already had e.g. Referrer-Policy come and break existing CSRF protection which treated an empty/missing Referer header as 'safe'. You're right that bad assumptions are going to made all over the place in the real world, but browser vendors shouldn't shoulder all of that responsibility.

You have to draw the line somewhere, right?


I worked a lot with client side bugs earlier, and clearly this trick has crossed this line. Browsers cannot say in one scenario that "content-type:application/json" are unsafe and in another allow completely unnecessary HEAD method that nobody ever used to be sent with 3rd party JS page.

Seriously who needs HEAD in their client side development? It's purely a technical method w/o clear use pattern. It's not even valid in <form method=""> so why would it be valid in fetch()? Oh and PATCH/PUT are still invalid in fetch().

We're lucky that this code pattern is only common in Rails. Otherwise it could open a whole class of bugs.


Wait, why is it useless? At minimum there is the example cited in the article of checking file length without having to download the actual file, but more generally, if headers have any value, and they must since they exist, why can't you imagine situations where you just want to see the headers without downloading a giant body?


For a client side code running on 3rd party page, there is no use case to let it send HEAD to you. Only GET and POST should be allowed by default, other methods only through CORS preflight. That was the premise of CORS. They broke it.


If GET is considered safe, HEAD must be as well. It's complete nonsense to claim HEAD is dangerous while GET is safe. Semantically, HEAD is literally just "do a GET but don't give me the body", so it should have the exact same server-side behavior as GET, except with the available optimization of not generating the response body (since it will be discarded).

The only reason this bug existed is because Rails treated HEAD as GET in some cases but not others. The sensible behavior here would be, in the Router, if the route didn't explicitly specify :head then it should convert the request to GET before handing it to the route. A route that wants to explicitly support HEAD (e.g. by skipping the response body) should explicitly specify :head on the route.

But the existence of this rails bug says nothing at all about the security of HEAD in general.


> The only reason this bug existed is because Rails treated HEAD as GET in some cases but not others

It is the main reason, yes, but not the only reason. If it wasn't possible to craft cross-site HEAD (which devs use in real life like.. never?) the bug would stop right there.

With an extra method if-else logic turned faulty. I would argue 90% web devs don't even remember of HEAD and what it means. Reasonably so, because it's rather never used.

IMO order of blame: 1) rails 2) browsers 3) github code relying on .get?


> If it wasn't possible to craft cross-site HEAD (which devs use in real life like.. never?) the bug would stop right there.

You're still focusing on the wrong thing. HEAD requests are largely obsolete at this point, yes, but that doesn't mean browsers would be right in changing the semantics of a HEAD request. The problem here isn't that browsers use the same security model for HEAD that they do for GET (as that's absolutely correctly) but that Rails decided to only partially support HEAD. Another simple fix for this bug would have been for Rails to simply give no special behavior to HEAD at all, and therefore any route that doesn't explicitly specify :head wouldn't be used for a HEAD request. The fact that Rails decided to deliver HEAD requests to a GET route without changing the request to actually appear as a GET request is a serious design mistake, and not one that browsers are responsible for.


Ok I can agree with that. This must definitely be discussed in rails/rails and fixed by design. I probably overplayed my concern with browsers.


Making sure the referer is correct is good enough. Other sites can't without permission send requests with a referer belonging to your site, and that won't change, unless the spec changes, and that's very very unlikely.


How about <img> on the page of the victim that triggers some CsRF with GET


Oauth is used in other places than browsers, HEAD has always been possible


I'm also not a fan of them, but I am even less a fan of the HTML spec for forms not supporting all methods.


But if your form is an advanced search form of instance, it should lead to a get request in my opinion.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: