50

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?

gtd
  • 16,956
  • 6
  • 49
  • 65

5 Answers5

29

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:
https://www.rfc-editor.org/rfc/rfc2817#section-4.2

Community
  • 1
  • 1
MicE
  • 5,038
  • 2
  • 29
  • 26
  • 3
    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. – Sripathi Krishnan Mar 31 '10 at 21:45
  • 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 Apr 01 '10 at 22:06
  • 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... – gtd Apr 02 '10 at 18:41
  • 5
    `https` as we know widely know it is specified in RFC 2818 (HTTP over TLS). RFC 2817 is virtually never used. @dasil003, note that IETF specs call TLS "TLS" because it's an IETF standard (SSL is not): you could easily read all of them with "SSL" in mind (except that it would refer to earlier versions indeed). RFC 2817 is not about upgrading to TLS (1.x) from SSLv3, it's about upgrading to SSL/TLS from plain HTTP, on the same connection. – Bruno Jan 22 '12 at 19:39
  • 7
    @SripathiKrishnan Even if your server would drop the http request, man-in-the-middle/intercept attack is still possible. Practically, unless the client is using https, it cannot be guaranteed that whatever response they get is not mangled. – Agoston Horvath Jul 11 '13 at 14:55
  • 3
    Definitely think the MITM discussion is overthinking it. MITM can intercept before you even have a packet to drop. If client attempts http, the deed is done. Purpose of 426 is to tell the client's developers to fix their darn code. – Matthew Mar 21 '17 at 19:31
9

The most secure way to force HTTP client to use HTTPS is HTTP Strict Transport Security.

Previously a common suggestion was to drop the connection, but this practice has been removed in favor of HSTS (OWASP website).

Brian Clozel
  • 56,583
  • 15
  • 167
  • 176
  • 6
    1. The HSTS draft has been [moved to the IETF](http://tools.ietf.org/id/draft-ietf-websec-strict-transport-sec). 2. reading it does not actually give a good answer to the OP's question. – David Moles Feb 12 '14 at 22:16
  • 2
    HSTS enforces HTTPS on the entire site. The above poster wanted some resource to be available over HTTP while others only over HTTPS. So HSTS cannot be used since it applies for all resources. – Fred Mar 18 '15 at 14:29
  • 2
    This doesn't answer the OP's question. He was asking about what to do when a client connects over http, not HSTS headers which only have effect when the user has already connected over https. – BadZen Dec 09 '15 at 17:48
  • You can preload HSTS in the browser to prevent any http call, https://hstspreload.org/ – Eric Apr 25 '23 at 00:54
7

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
  • 52,000
  • 11
  • 64
  • 62
  • 4
    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 Mar 31 '10 at 21:26
  • 1
    Yeah, as appealing as that subcode is I can't behind the non-standardized nature of it. – gtd Apr 01 '10 at 18:28
  • 4
    I agree with other commenters that a subcode should not be used, but a case could be made for a plain 403. For example, that's what Twitter is using for their API. See https://dev.twitter.com/docs/security/using-ssl – Chris H. Apr 17 '14 at 00:57
7

Returning a 403 with reason phrase "HTTPS Required" seems like a practical option and what I use.

see https://en.wikipedia.org/wiki/HTTP_403

Redirecting a REST Api is not a good idea especially as you may have no idea as to how or what is consuming your service.

NER1808
  • 1,829
  • 2
  • 33
  • 45
0

Just send a redirect to the corresponding https: URI.

UPDATE

The is a wrong answer - see comments below

Jan Algermissen
  • 4,930
  • 4
  • 26
  • 39
  • 2
    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 – Sripathi Krishnan Mar 31 '10 at 21:39
  • 2
    That does not stop users from still referring to the http url, in fact, with most http clients they won't even see that an http redirect took place. Sweeping the problem under the rug is probably not the approach you want to take. – Agoston Horvath Jul 11 '13 at 14:49
  • 2
    Yes, sorry. You guys are right. Sending a redirect is the wrong thing to do. Thanks for pointing that out. – Jan Algermissen Jul 13 '13 at 15:16