Chapter 10
HTTPS, Certificates, and Security Headers
What a Certificate Proves
Count the places where this course said “only over HTTPS”. The Secure, so a browser sends it over HTTPS and nowhere else. Its name starts with __Host-, which a browser accepts only from an HTTPS response. Basic credentials are the password in
A name, a key, an issuer, and two dates
A server that speaks TLS presents a certificate. Here are five lines of the test certificate this chapter uses, as the openssl tool prints them:
Issuer: O=Python Land course tests, CN=TEST ONLY Python Land Web Security course authority
Not Before: Nov 1 00:00:00 2026 GMT
Not After : Nov 1 00:00:00 2046 GMT
Subject: O=Python Land course tests, CN=TEST ONLY reading
DNS:reading.example, DNS:app.reading.example, DNS:notes.reading.example, DNS:localhost, IP Address:127.0.0.1
The last line
A certificate is public. The server sends it to every client that connects, and anyone can copy it. What an impostor lacks is the private key that belongs to the public key in the file. During the TLS handshake the server proves that it holds that private key, without revealing it. A copied certificate without the key proves nothing.
What does a certificate tie together?
Signed by someone you already trust
Anyone can write a file that says “this key belongs to reading.example”. A certificate counts because an issuer signed it. An issuer is also called a certificate authority; this lesson says issuer.
In Chapter 2 you protected a message with an
An issuer’s signature is a different kind of signature, a public-key signature. The issuer signs with a private key that it never shares. Anyone can check the signature with the issuer’s public key, and checking gives no power to sign. This course does not build such signatures; it is enough to know which property they have that a keyed tag lacks.
That leaves one question: where does the client get the issuer’s public key? It starts with a list of issuers it trusts, installed with the
Why does an issuer not protect a certificate with an HMAC tag, like the one you made in Chapter 2?
Three checks
Before a client sends a single byte of a request, it makes three checks on the certificate:
Issuer. Was it signed by an issuer on my list?
Name. Is it for the name I asked for?
Date. Is today inside its period?
Here is a model of the three checks. It is a model: a real client checks signatures where this code compares names. Dates written year, month, day compare correctly as text, so the model keeps them as
The first three calls print accepted, refused: wrong name, and refused: unknown issuer. Each refusal names one check. The name check is the one people forget: a trusted issuer signs certificates for millions of sites, so “signed by a trusted issuer” says nothing until the name matches too.
You connect to reading.example. The server presents a certificate that an issuer you trust made for other.example, valid today. Which check fails?
What does the fourth call in the block above print?
What a certificate does not say
A valid certificate tells you that you are talking to a server that holds the key for the name you asked for, and that an issuer you trust has confirmed it. It tells you nothing else. It does not say who runs the site, what the site does with a password, or whether its code is safe. For the usual kind of certificate, an issuer checks that the applicant controls the name, and that is all it checks. Some certificates also name an organization. A client does not look at that: it checks the name. A site that stores passwords as plain text can have a perfectly valid certificate.
One more limit, for recognition only. An issuer can withdraw a certificate before its end date, which is called revocation. Python’s default context does not check for that.
A site shows a valid certificate for the name you typed. What do you know?
You can now say what a client checks. Nothing in your project makes those checks yet. The next lesson builds the