views:

105

answers:

4

I'm designing an RESTful API where some calls are public over HTTP, and some require an API key and encryption over HTTPS. I'm deliberating on what response code should be sent if an HTTP request is sent to one of the private resources. So far the only one that jumps out at me is 412 - Precondition Failed, but the standard indicates that the precondition is imposed by the requester not the server.

Is there an appropriate response code for this condition or do I just need to give in and do 400?

+2  A: 

The appropriate error code to return would be similar to 403.4 - SSL required.

Although not explicitly documented in the RFC for HTTP 1.1, this behavior does match the requirements outlined there:

The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead.

Adding your own subcode (as with the SSL example) might be helpful in some cases, but since this subcode would not be meaningful to third parties, I would recommend against it.

So, your final error message would be something like "403 - Private Resource". Note that, even in the case of a missing API key, "401 - Unauthorized" should not be used, unless your API key can actually be transmitted in a WWW-Authenticate header field.

mdb
Note that the IIS status codes are bogus. HTTP status codes are composed of numbers only (3 exactly). See http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1.1 Also note that the reason phrase for 403 is "Forbidden" and that this is not subject to modification. Any further explanation should go into the response *body*.
Jan Algermissen
Yeah, as appealing as that subcode is I can't behind the non-standardized nature of it.
dasil003
+2  A: 

Recommended approach is to drop the connection altogether - i.e. no response at all. Thus you don't need any status code.

Reference - OWASP SSL Best Practices. Search for Http connections should be dropped.

sri
I can see how this would be the best response, however given this is being set at the application level in a Rails app I don't think I have a convenient way to tell the webserver to drop the connection. Plus this is harder to document than a straight response code. Therefore on balance I gotta go with MicE's solution. Definitely +1 on this though, thanks.
dasil003
I changed my accepted answer for reasons stated above. Unfortunately I still have no way to drop the connection. I think I will return 403 instead. I was thinking about the security implications of returning 403, and I fail to see how it's a significant risk. A man in the middle could fabricate any response they want anyway even if the connection was dropped, and it's not clear what information he could extract out of a Forbidden respone, so it doesn't seem to really decrease security in any way. Am I missing something?
dasil003
+2  A: 

I cannot say if this is broadly accepted by HTTP clients, but speaking strictly RFC, the server should respond with:

HTTP/1.1 426 Upgrade Required
Upgrade: TLS/1.0, HTTP/1.1
Connection: Upgrade

Source:
http://tools.ietf.org/html/rfc2817#section-4.2

MicE
Interesting. RFC and OWASP differ in their recommendations. I prefer OWASP's version - don't respond to the request and just drop the packet. With the RFC approach, a man-in-the-middle could intercept the response (since it isn't https yet) and redirect to a spoofed website.
sri
Yes, I agree - it's definitely a vulnerability. Even if dropping the connection might be confusing, security concerns should take precedence here. Also, note that the mentioned RFC is now practically 10 years old (in those times security might not have been such an important aspect as it is today).
MicE
You know, after looking closer at this I realized this is for an upgrade to TLS, presumably from some earlier version of SSL. I'm not doing TLS, so I can't use that header, and since the spec is specifically for TLS I don't think this is appropriate. Unfortunately I also don't have a way to drop the connection...
dasil003
A: 

Just send a redirect to the corresponding https: URI.

Jan Algermissen
There's a security risk. "An attacker performing a man in the middle attack could intercept the HTTP redirect response and send the user to an alternate page" - from OWASP SSL Best Practices
sri