ASVS 5.0 V4.1.2 (level 2) says that only user facing endpoints, the ones people open in a browser, should automatically redirect from HTTP to HTTPS. API endpoints and service to service endpoints should not redirect. They should refuse plain HTTP outright.
The reasoning is about visibility. If a mobile app or a script calls http://api.example.com/orders by mistake and your server answers with a 301 to HTTPS, the call works. Nobody notices. But the first request already crossed the network in cleartext, with its bearer token and body. A hard failure would have been caught in the first test run.
Why it matters
A redirect hides a bug that leaks secrets. The client library follows the redirect, the response comes back fine, and the developer sees green tests. Meanwhile the Authorization header travelled unencrypted on the first hop, where anyone on the path can read it. Redirecting also invites downgrade tricks, since the very first request is the one an attacker can intercept.
For browsers the trade is different. People type bare domain names, so a redirect is the friendliest way to land them on HTTPS, and HSTS then pins the choice for later visits. That is why the requirement splits the two cases. See CWE-319 for the cleartext transmission weakness behind it.
How to implement it
Split your hostnames by audience. Serve the website on www.example.com and the API on api.example.com, then give each its own port 80 behavior.
For the site, redirect and send HSTS on the HTTPS response:
server {
listen 80;
server_name www.example.com example.com;
return 301 https://www.example.com$request_uri;
}
For the API, either do not listen on port 80 at all, or answer with a clear error that is not a redirect:
server {
listen 80;
server_name api.example.com;
default_type application/json;
return 400 '{"error":"https_required"}';
}
The best option is to close port 80 on API hosts at the load balancer or firewall. A refused connection is the loudest failure there is. Add Strict-Transport-Security on the HTTPS API responses too, and make your own SDKs build https:// URLs only.
How to test it
Run these against each host and compare with what the host is for.
curl -sS -o /dev/null -w "%{http_code} %{redirect_url}\n" http://www.example.com/
curl -sS -o /dev/null -w "%{http_code} %{redirect_url}\n" http://api.example.com/v1/health
The first should print a 301 or 308 with an https:// target. The second must not print any 3xx. Expect a 400, a 403, or a connection refused error. Also grep your client code and mobile app config for hard coded http:// base URLs, and check that integration tests fail when pointed at plain HTTP.
Common mistakes
- Putting a catch all redirect on port 80 for every hostname because the template came that way.
- Serving the API and the website from one hostname, which forces one policy on both.
- Closing port 80 on the API but leaving a second load balancer or CDN edge that still redirects.
- Treating HSTS as a replacement. HSTS only helps clients that already saw the header over HTTPS.
- Letting HTTP clients follow redirects silently with default settings. Disable redirect following for service calls where you can.
Quick check
Why not redirect API traffic from HTTP to HTTPS?
Because the redirect hides a client that sends data in cleartext. The first request already leaked its headers and body, and nobody sees a failure to fix.
Sources
- OWASP Application Security Verification Standard, requirement V4.1.2 (level 2)
- RFC 6797, HTTP Strict Transport Security