Why plain HTTP is a gamble

An HTTP request travels from router to router until it reaches its destination, and every machine along that path sees everything you send. That includes credentials, session cookies, and the full contents of responses. None of it is encrypted, and none of it can be verified as untouched.

A malicious middleman can read the traffic, modify it, and serve you something entirely different — and you would never know. A modified HTTP response is indistinguishable from a legitimate one, because the protocol has no integrity mechanism at all. This makes interception not just possible but practically invisible.

HTTPS closes the channel

Encrypting the connection with HTTPS is the fundamental defense against this. An HTTPS session establishes an end-to-end encrypted channel before any application data flows, so machines in between cannot read or alter what passes through.

The security model rests on public/private key cryptography. The server presents a certificate during the handshake, and the browser verifies that the server actually holds the corresponding private key. Once that verification succeeds, all communication is encrypted to and from that authenticated server.

This gives you two guarantees: you are talking to the server you think you are talking to, and no one else is listening in or modifying traffic. If your application is not served over HTTPS, it is exposed to attack. Obtaining and installing a certificate is the first step; the process for requesting one is the same everywhere, though server configuration details will vary by provider and platform.

Make HTTPS the default path

Once a certificate is installed, users should not have to opt into security. You can migrate them automatically with a redirect, and you should ensure that their session data never travels over a plaintext connection.

Redirect from HTTP

When a request arrives at http://example.com/, respond with a 301 Moved Permanently status and a Location header pointing to the HTTPS version of the same URL. This can be configured in servers like Apache or Nginx with a small rule:

server {
    listen [YOUR IP ADDRESS HERE]:80;
    server_name example.com www.example.com;
    location "/" {
        rewrite ^(.*) https://www.example.com$1 permanent;
    }
}

Restrict cookies to secure connections

Cookies carry session identifiers and other sensitive state on every request. A normal Set-Cookie header looks like this:

set-Cookie: KEY=VALUE; path=/; expires=Sat, 01-Jan-2022 00:00:00 GMT

Add the Secure keyword to tell the browser the cookie is only valid over an encrypted connection:

Set-Cookie: KEY=VALUE; path=/; expires=Sat, 01-Jan-2022 00:00:00 GMT; secure

With that flag set, browsers will never transmit the cookie over plain HTTP.

Close the HTTP window with HSTS

Server-side redirects cover most traffic, but they leave the initial HTTP request exposed. A man in the middle can intercept that first connection and keep you on HTTP, proxying requests to the server and stripping away the security upgrade. This is the classic SSL-stripping attack, and the user never sees it.

HTTP Strict Transport Security (HSTS) closes that hole by moving the redirect decision into the browser. Sending the Strict-Transport-Security header tells the browser to perform the HTTP-to-HTTPS upgrade client-side, before any network request is made. That also saves a round trip:

$ curl -I https://mkw.st/
HTTP/1.1 200 OK
Server: nginx/1.3.7
...
Strict-Transport-Security: max-age=2592000

Browsers that support HSTS make a note that the site requires HTTPS, so typed-in or clicked HTTP URLs never result in a plaintext request. If the browser detects a certificate problem, the user cannot fall back to HTTP — connection is all or nothing.

The max-age directive controls how long the browser remembers the policy, expressed in seconds. Set it to a reasonably long value. To protect all subdomains of the origin as well, add the includeSubDomains directive:

$ curl -I https://mkw.st/
HTTP/1.1 200 OK
Server: nginx/1.3.7
...
Strict-Transport-Security: max-age=2592000

Putting it together

Securing a site against malicious intermediaries is a three-step process. First, obtain and install a certificate so HTTPS is actually possible. Second, redirect all plaintext requests to the secure version with a 301 response, and mark session cookies with the Secure attribute so they are only sent over the encrypted channel. Third, send the Strict-Transport-Security header so that browsers enforce HTTPS themselves and users never fall back into an unencrypted session.

None of these steps are particularly difficult, and together they ensure that data reaches its intended recipient intact and unread by anyone in between.