DNS, HTTP & HTTPS

Cyber Security · Lesson 7 of 31 7 min read Updated

When Isha types a shopping site's name into her browser, two protocols do most of the work. DNS finds the server's IP address, and HTTP (inside HTTPS) carries the request and the page. Attackers target both: fake DNS answers send users to the wrong server, and weaknesses in HTTP handling lead to stolen sessions.

In this lesson you will learn how DNS resolution works and which records matter for security, how HTTP requests and responses are built, what HTTPS protects, and how to check a website's security headers with Python.

DNS: the internet's phone book

DNS (Domain Name System) turns names such as shop.example into IP addresses. Your computer asks a recursive resolver (usually run by your internet provider or a public service). If the resolver does not already know the answer, it asks the root servers, then the servers for the top-level domain (such as .in or .com), and finally the domain's authoritative server, which holds the real records. Answers are cached for a time called the TTL (time to live).

RecordHoldsSecurity relevance
AAn IPv4 addressWhere the site really is
AAAAAn IPv6 addressDo not forget IPv6 when you secure a server
CNAMEAn alias pointing to another nameOld aliases to deleted cloud services can be taken over
MXMail servers for the domainWhere email for the domain is delivered
TXTFree text, including SPF and DMARC email policiesHelps receivers reject forged email
NSThe authoritative name serversWhoever controls these controls the domain

This small resolver follows a CNAME chain the way real resolvers do, using a dictionary instead of the network:

PythonRun it yourself
records = {
    "www.shop.example": ("CNAME", "shop.example"),
    "shop.example": ("A", "203.0.113.25"),
    "old.shop.example": ("CNAME", "shop-old.cloudapp.example"),
}

def resolve(name, depth=0):
    if depth > 5:
        return "error: CNAME loop"
    if name not in records:
        return "NXDOMAIN (name does not exist)"
    kind, value = records[name]
    print("  " * depth + f"{name} -> {kind} {value}")
    return value if kind == "A" else resolve(value, depth + 1)

print("Answer:", resolve("www.shop.example"))
print("Answer:", resolve("old.shop.example"))
Output
www.shop.example -> CNAME shop.example
  shop.example -> A 203.0.113.25
Answer: 203.0.113.25
old.shop.example -> CNAME shop-old.cloudapp.example
Answer: NXDOMAIN (name does not exist)

The second lookup shows a dangling CNAME: the alias points at a cloud name that no longer exists. If an attacker can register that cloud name, they control old.shop.example. This is called subdomain takeover, and the fix is to delete DNS records when you delete the service they point to.

Other DNS threats include cache poisoning (tricking a resolver into storing a false answer) and look-alike domains used in phishing. DNSSEC adds digital signatures to DNS answers, and DNS over HTTPS (DoH) or DNS over TLS (DoT) encrypt the lookup between your device and the resolver.

On Kali you can query DNS with dig or nslookup. Use names you own or the reserved example.com:

Terminal
dig example.com A +short
dig example.com MX
nslookup example.com

HTTP requests and responses

HTTP is a text protocol. The browser sends a request with a method, a path, headers and sometimes a body. The server sends back a response with a status code, headers and a body.

Text
POST /login HTTP/1.1
Host: shop.example
Content-Type: application/x-www-form-urlencoded
Cookie: lang=en

email=farhan%40mail.example&password=correct-horse

Common methods are GET (read), POST (send data), PUT and PATCH (update) and DELETE. Status codes are grouped: 2xx success (200 OK), 3xx redirect (301, 302), 4xx client error (401 not logged in, 403 forbidden, 404 not found) and 5xx server error (500).

HTTP itself is stateless: each request stands alone. To remember a logged-in user, the server sends a cookie with a random session ID, and the browser sends it back with every request. Whoever has that session cookie is the user, which is why stealing cookies is so valuable to attackers.

Newer versions, HTTP/2 and HTTP/3, send the same requests more efficiently (HTTP/3 runs over QUIC on UDP), but the methods, headers and security ideas are unchanged.

What HTTPS adds

HTTPS is HTTP sent inside a TLS connection. TLS gives three protections:

  • Confidentiality: people on the same Wi-Fi cannot read passwords or cookies.
  • Integrity: nobody can change the page or the request on the way.
  • Authentication: the server proves, with a certificate, that it really is shop.example.

HTTPS does not mean a site is honest or safe. A phishing site can have a perfectly valid certificate for its own look-alike domain. You will see how TLS and certificates work in Digital Signatures, Certificates & TLS.

Python's urllib.parse splits a URL into its parts, which is useful when checking links:

PythonRun it yourself
from urllib.parse import urlsplit, parse_qs

url = "https://shop.example:8443/orders/view?id=1042&lang=hi#top"
parts = urlsplit(url)

print("Scheme:  ", parts.scheme)
print("Host:    ", parts.hostname)
print("Port:    ", parts.port)
print("Path:    ", parts.path)
print("Query:   ", parse_qs(parts.query))
print("Fragment:", parts.fragment)
Output
Scheme:   https
Host:     shop.example
Port:     8443
Path:     /orders/view
Query:    {'id': ['1042'], 'lang': ['hi']}
Fragment: top

The fragment (#top) is never sent to the server; it stays in the browser.

A server can tell the browser to apply extra protections using response headers. Every web tester checks these:

HeaderWhat it does
Strict-Transport-SecurityHSTS: always use HTTPS for this site, even if the user types http://
Content-Security-PolicyLimits where scripts, styles and frames may load from; a strong defence against XSS
X-Content-Type-Options: nosniffStops the browser guessing file types
X-Frame-Options or CSP frame-ancestorsStops other sites loading yours in a frame (clickjacking)
Referrer-PolicyLimits how much of the URL is sent to other sites

Cookies have flags too: Secure (only send over HTTPS), HttpOnly (JavaScript cannot read it) and SameSite (Lax or Strict limits sending it on requests from other sites). This checker reviews a response captured from a lab app:

PythonRun it yourself
response = """HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
X-Content-Type-Options: nosniff
Set-Cookie: session=8f2c1d; Path=/; HttpOnly
Server: Apache/2.4.58 (Ubuntu)"""

lines = response.splitlines()
headers = {}
for line in lines[1:]:
    name, _, value = line.partition(": ")
    headers[name.lower()] = value

wanted = ["strict-transport-security", "content-security-policy", "x-content-type-options", "referrer-policy"]
for h in wanted:
    print(f"{'OK     ' if h in headers else 'MISSING'} {h}")

cookie = headers.get("set-cookie", "")
for flag in ["Secure", "HttpOnly", "SameSite"]:
    print(f"{'OK     ' if flag.lower() in cookie.lower() else 'MISSING'} cookie flag {flag}")
print("Server header reveals:", headers.get("server", "nothing"))
Output
MISSING strict-transport-security
MISSING content-security-policy
OK      x-content-type-options
MISSING referrer-policy
MISSING cookie flag Secure
OK      cookie flag HttpOnly
MISSING cookie flag SameSite
Server header reveals: Apache/2.4.58 (Ubuntu)

The Server header reveals the exact software version, which helps attackers look up known vulnerabilities. Hiding it is not a fix by itself, but there is no reason to advertise it.

To see real headers from your lab app, run curl -I http://192.168.56.101:3000 on Kali.

Common mistakes

  • Thinking the padlock means "safe". HTTPS protects the connection, not the honesty of the site.
  • Leaving old DNS records behind. Dangling CNAMEs lead to subdomain takeover.
  • Session cookies without Secure and HttpOnly. They can leak over plain HTTP or be read by injected scripts.
  • Putting secrets in URLs. URLs end up in browser history, server logs and Referer headers. Send secrets in the body or headers.

Key points

  • DNS resolves names through resolvers, root, TLD and authoritative servers, with caching by TTL.
  • A, AAAA, CNAME, MX, TXT and NS records each matter for security; delete records for retired services.
  • HTTP is stateless text; cookies carry session IDs, so stolen cookies mean stolen sessions.
  • HTTPS (HTTP over TLS) gives confidentiality, integrity and server authentication, but not trustworthiness.
  • Check security headers (HSTS, CSP, nosniff) and cookie flags (Secure, HttpOnly, SameSite).

Exercise

Extend the header checker so that it also reports MISSING for x-frame-options unless the content-security-policy header contains frame-ancestors. Test it with a response that has Content-Security-Policy: default-src 'self'; frame-ancestors 'none' and no X-Frame-Options header.

Show solution
Python
response = """HTTP/1.1 200 OK
Content-Security-Policy: default-src 'self'; frame-ancestors 'none'"""

headers = {}
for line in response.splitlines()[1:]:
    name, _, value = line.partition(": ")
    headers[name.lower()] = value

csp = headers.get("content-security-policy", "")
if "x-frame-options" in headers or "frame-ancestors" in csp:
    print("OK      clickjacking protection")
else:
    print("MISSING clickjacking protection")

It prints OK clickjacking protection, because the CSP frame-ancestors directive does the same job as X-Frame-Options in modern browsers.

Quick Quiz

1. Which DNS record type holds an IPv6 address?

2. What does the HttpOnly cookie flag do?

3. What does HTTPS NOT guarantee?

4. What is a dangling CNAME?

Learn Cyber Security with a mentor

Free lessons get you started. Our Ethical Hacking & Cyber Security training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call