4

I have an HTTP serving an API which works either anonymously or with a secret key in a header, like so:

GET /profile?authenticationKey
Authorization: 1234567890

I want to reject any request coming in over HTTP that uses an Authorization header, since those headers would come across in plain text. But I'm not sure what the appropriate response is.

I've considered 400 Bad Request with a note explaining why what they did was stupid and suggesting that they immediately invalidate their key.

But I'm wondering whether 426 Upgrade Required might be better or worse. It's a code specific to the idea that an HTTP request needs to be an HTTPS request, but reading RFC 2817 makes me think that it is designed to help switch to HTTPS from the same port. Can I use it in this case as well? If so, do I need to include an Upgrade: TLS/1.0 header as well?

user2719333
  • 49
  • 1
  • 2

1 Answers1

8

The situation you are trying to avoid here is that of API users sending their credentials over the wire in a form easily sniffed by third parties.

If you either redirect to HTTPS or serve any HTTP error, you don't avoid this situation; the credentials are already sent before you have a chance to respond.

The only really proper thing to do is to not serve the API on HTTP at all, not even for anonymous requests. For your API server, ideally there should not be a server listening on port 80 at all. If you must have that IP address listening on port 80 (e.g. because you don't have any spare IP addresses), then you should return 403 Forbidden or 404 Not Found for API requests. Optionally you could capture and invalidate such credentials as were sent mistakenly over HTTP, but it's best to simply not listen on HTTP at all.

Michael Hampton
  • 2,960
  • 2
  • 17
  • 18
  • I'll give you a real world example of this sort of problem. Amazon S3 is a RESTful API that works on HTTP and HTTPS. It supports optional customer-provided encryption keys, which are transmitted in a header. Most users do not use that feature, but if they do want to use it, they must use HTTPS. Are you saying that the only really proper thing for S3 to do is not support HTTP at all? – user2719333 Oct 27 '15 at 20:47
  • The users don't _have_ to use HTTPS in that scenario, but then their credentials go out over the wire exposed. If you want to completely eliminate this possibility, you can't offer your API via HTTP at all. – Michael Hampton Oct 27 '15 at 20:49
  • Well, in any case, S3's actual decision, to simply allow the request to succeed while ignoring the headers completely, therefore storing the objects in plaintext, appears to be completely insane. So I will allow that your option is better, although I still think a 400 is a perfectly valid response. – user2719333 Oct 27 '15 at 22:06
  • 1
    @Bob From the RFC: "The 400 (Bad Request) status code indicates that the server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing)." I guess that _sort of_ fits, but it's hardly ideal. – Michael Hampton Oct 27 '15 at 22:10
  • I'm unsure of how "not listening on port 80" prevents the request from being intercepted by a third party? I agree the client is making a mistake... but even if there's no listener on port 80, I assume the request will still be visible to anyone sniffing traffic. So if that is true, it seems valid to return _something_ useful, rather than the client wondering why it isn't working. – Jason Capriotti Feb 07 '22 at 22:45