Start learning free

LESSON 19 OF 20 · SECURITY: INTERVIEW QUESTIONS

A Reset Link to the Attacker's Site in Python

Practice

An interviewer shows you how a shop builds its password reset email and asks: "Where does this link point, and who decides that?"

token = secrets.token_urlsafe(32)
RESETS[hash_token(token)] = email
link = request.host_url + "reset?token=" + token
# ... then the link is emailed to the account's address

request.host_url is built from the request's Host header, and whoever sends the request writes that header. An attacker posts /forgot with Ana's email and Host: evil.example, and the shop emails Ana a genuine message with a link to http://evil.example/reset?token=…. What the attacker gets: when Ana clicks, her token lands on the attacker's site, and the attacker uses it to choose her new password.

The fix: the shop's own address is a setting, not something to read from the request. Read it once from an environment variable, with a default for your own laptop. A shop could read the address of its image server the same way:

CDN_URL = os.environ.get("CDN_URL", "http://localhost:8080")
image = CDN_URL + "/img/" + filename

The check runs your shop with SHOP_URL set to https://shop.example.com and reads the last email sent at GET /check/last-mail. It must see:

POST /forgot  {"email": "ana@example.com"}
  →  200  {"message": "If that email has an account, a reset link is on its way"}
GET /check/last-mail
  →  200  {"emails": 1, "link": "https://shop.example.com/reset?token=…", "to": "ana@example.com", …}
POST /forgot  {"email": "ana@example.com"}  with the header Host: evil.example
  →  200  {"message": "If that email has an account, a reset link is on its way"}
GET /check/last-mail
  →  200  {"emails": 2, "link": "https://shop.example.com/reset?token=…", "to": "ana@example.com", …}
POST /reset  {"token": "…the emailed token…", "password": "new-pass-456"}
  →  200  {"message": "Password changed, you can log in"}
POST /reset  {"token": "…the same token…", "password": "attacker-pass-1"}
  →  400  {"error": "This reset link is invalid or has expired"}

Your task: set SHOP_URL from the environment, with "http://localhost:5000" as the default, build the reset link from it in forgot, and post the email to MAIL + "/send".


Assignment
Follow the Coding Tutorial to build the reset link from a configured SHOP_URL and email it to the account's address.


Hint
Don't use request.host_url or request.url_root for links you send out: both come from the Host header. os.environ.get(name, default) works like a dictionary's get.


STEP 1 OF 3
    Ctrl + Enter to check

    Secq Host Header in Python

    Keep going with Python1,600+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free