skip to content

Why does RFC 7617 require HTTP Basic authentication to be used only over a confidential channel such as TLS, and what concretely goes wrong if a service accepts Basic over plaintext HTTP?

level: middleimportance: must knowfreq 58%

answer

  1. scheme provides zero confidentiality — channel provides all
  2. long-lived password, not a bounded token
  3. resent every request = huge exposure window
  4. http→https redirect is too late: header already sent
  5. HSTS, no plaintext listener, redact Authorization in logs

basics

~20 s

Basic transmits the reusable password itself, base64-encoded, on every single request. Without TLS any observer — network tap, proxy, log — reads and replays it forever. TLS is the only thing supplying confidentiality; the scheme supplies none.

solid answer

~50 s

Basic has no cryptographic protection of its own: the credential is `base64(user:password)`, reversible in one step. Three properties make plaintext use catastrophic rather than merely risky. 1. **The secret is the password, not a derived token.** Capture it and you own the account until it is rotated — and, thanks to password reuse, often other accounts too. 2. **It is replayed on every request.** There is no single login moment to protect; a session of a thousand requests gives an attacker a thousand chances. 3. **It is directly replayable.** Unlike a nonce-based scheme, a captured header works verbatim on any later request. So the server should refuse Basic when the request did not arrive over TLS — and importantly, redirecting `http://` to `https://` is not a fix: the client already sent the header in the clear before the redirect. Enforce HSTS, terminate TLS at the edge, keep the internal hop encrypted or trusted, and scrub `Authorization` from access logs and APM traces.

code

bash · 5 lines
bash
# Leaks the credential in cleartext BEFORE the redirect is received
curl -u alice:s3cret http://api.example.com/reports

# Refuses to speak anything but TLS; a bad URL errors instead of leaking
curl --proto '=https' -u alice:s3cret https://api.example.com/reports

go deeper

for a junior

Say that base64 is reversible, so without TLS the password is effectively sent in the clear, and that it is sent on every request.

for a middle

Add why the credential is worth more than a token (long-lived, reusable, directly replayable) and why the http→https redirect does not save you.

for a senior

Cover enforcement: reject Basic when X-Forwarded-Proto is not https, HSTS and preload, header redaction across logs and tracing, credential rotation after any plaintext sighting.

for a principal

Reason about the TLS-termination boundary as a threat-model decision, and about whether long-lived passwords belong in the architecture at all versus short-lived, scoped, revocable credentials.

## The scheme contributes nothing RFC 7617 states plainly that Basic does not provide confidentiality, integrity or protection against replay. Every security property must come from the channel. Base64 is an encoding chosen so the credential survives an HTTP header, not a protection — `base64 -d` reverses it with no key. So the honest way to describe Basic is: *the password travels across the wire in a lightly obfuscated form, on every request*. ## Why plaintext Basic is worse than plaintext in general Three properties compound. **The credential is the long-lived password.** Token schemes leak a bounded, expiring artifact. Basic leaks the account secret itself. It can be used from anywhere, cannot be revoked without a password reset, and — because humans reuse passwords — is worth trying at the victim's other services. **Statelessness multiplies exposure.** Because Basic keeps no session, the header rides on every request in the protection space: API polls, health checks, retries, image fetches. An attacker does not need to catch a login; catching any one request suffices. A background job hitting an endpoint every 30 seconds broadcasts the password 2,880 times a day. **Replay is trivial.** The header is a constant. Copy it into `curl` and you are authenticated. Digest-style schemes at least involve a server nonce; Basic has none. ## Who actually sees a plaintext request This is where candidates often say "nobody can sniff our traffic". Realistic observers include: anyone on a shared or hostile network (café Wi-Fi, hotel, conference); an on-path attacker doing ARP or DNS spoofing; a transparent or corporate proxy; a compromised switch, VPN concentrator or ISP middlebox; any load balancer or reverse proxy that logs full request headers; a service mesh sidecar; and — a very common real leak — the observability stack, where a plaintext capture, a `tcpdump` on a debug host or an HTTP-trace log ends up in a log store readable by the whole engineering org. ## The redirect trap A frequent wrong answer is "we redirect HTTP to HTTPS, so it's fine". It is not. Clients that send Basic preemptively — which is the norm for API clients and `curl -u` — put the `Authorization` header on the *first* request. If that first request went to `http://`, the credential was already transmitted in the clear; the 301 arrives afterwards and only protects the retry. The password is burned. Mitigations that actually work: never open a plaintext listener for the API at all, or open it only to serve the redirect and treat any credential seen there as compromised; ship HSTS (`Strict-Transport-Security: max-age=63072000; includeSubDomains; preload`) so browsers never attempt plaintext again; configure clients with `https://` base URLs; use `curl --proto '=https'` in scripts so a mistyped URL fails instead of leaking. ## TLS termination and the internal hop Most production topologies terminate TLS at a load balancer or ingress and forward plaintext HTTP inside. Whether that is acceptable is a threat-model question, not a yes/no: the internal segment must be one you would be comfortable having an attacker read, since the password is visible on it to anything with packet capture or header logging — including sidecars and mesh proxies. If the mesh already provides mTLS between pods, re-encryption is inherent; if not, either enable it or accept that any internal compromise yields the plaintext password. The application should also be able to *tell*: honour `X-Forwarded-Proto` (only from a trusted proxy) and reject Basic when the original scheme was not `https`. ## Hardening checklist - Reject Basic on non-TLS requests outright — a 400 or a challenge, never a success. - Serve HSTS and preload; disable plaintext listeners where possible. - Redact `Authorization` in access logs, request tracing, error reporters and HAR captures. Redaction must be allow-list based; header names are case-insensitive and easy to miss. - Keep credentials out of URLs (`https://user:pass@host` is deprecated and lands in logs and history) and out of shell command lines. - Rate-limit and lock out per user id and per source, since the password is directly guessable. - Rotate any credential ever observed on a plaintext path; treat that as an incident, not a warning. ## The honest summary "Basic over TLS" is a reasonable design for machine-to-machine calls. "Basic" without TLS is not a weaker design; it is the publication of a password to everyone on the path, repeated on every request.

  • Our edge terminates TLS and forwards plain HTTP to the pods. Is that acceptable for Basic?
    It depends on the trust you place in that internal segment, because the password is readable there by anything that can capture packets or log headers — sidecars, mesh proxies, a debugging tcpdump. Either encrypt the internal hop (mesh mTLS or HTTPS upstreams) or accept that an internal foothold yields the plaintext password. Either way the app should reject Basic when the trusted proxy reports `X-Forwarded-Proto: http`.
  • If the service redirects all HTTP traffic to HTTPS, why is that not enough?
    Clients that send Basic preemptively — API clients and `curl -u` — attach the `Authorization` header to the very first request. If that request used `http://`, the credential was already on the wire in the clear; the redirect only protects the retry. The fix is to never accept a plaintext request for the API, ship HSTS, and treat any credential seen on a plaintext path as compromised.

saying these in an interview costs you the question

  • "It's base64-encoded so it isn't really plaintext"
  • "We redirect HTTP to HTTPS, so credentials are safe"
  • "It's an internal network, nobody can sniff it" — with no threat model for proxies, sidecars or header logging
  • Forgetting that the credential is resent on every request, not just at login
  • Not mentioning log/APM redaction of the Authorization header

context