0%

What Can Go Wrong

Write a Finding

“The look risky” is a feeling. Nobody can fix it, and nobody can test whether it has been fixed. A finding is the same suspicion written down so that both are possible.

This lesson gives a finding its shape, works one example in full, and then has you complete two more. In the next lesson they go into SECURITY.md, the file in your project that what is wrong with the service.

Four parts

A finding answers four questions.

  • Exposed. What does an attacker get to read or change? Name the asset.

  • Attack. How do they reach it, and what must they already have? Name the attacker.

  • Fix. What change would close it?

  • Proof. What would show that it is closed? The strongest proof is a test that performs the attack and fails today.

The first two parts come straight from the threat model of the last lesson: an asset, and an attacker with a certain reach. The last two make the finding useful. A fix says what to do. A proof says how you will know.

A worked finding

Here are the tokens your server accepts, as sample_state() builds them:

"tokens": {
    "tok-ana-writes-7Qx2": {"user": "ana", "can_write": True},
    "tok-ben-reads-K9pz": {"user": "ben", "can_write": False},
},

Take it through the four parts.

  • Exposed: the power to add, change, and delete books as ana.

  • Attack: the writing token is a fixed in the source. Anyone who reads the file, or a backup of the state, has it. It never stops working.

  • Fix: a token the server makes itself, that only the server could have made, and that expires.

  • Proof: a test that sends the old string tok-ana-writes-7Qx2 with a write and expects 401.

Each part is one or two sentences, and each names something specific. This is finding F6 in the course’s numbering, and Chapter 5 closes it. You do not need to fix it now. Writing it down is the work of this chapter.

Which statement is a finding you could fix and test?

Your turn, with half filled in

Now the session store. These are the two places in your server that deal with how long a session lasts:

def start_session(state, user):
    """Store a new session for user under a random id and return the id."""
    session_id = secrets.token_urlsafe(16)
    state["sessions"][session_id] = {"user": user}
    return session_id

and, in session_cookie(), the line cookie["session"]["max-age"] = max_age, where max_age is 3600 unless the caller says otherwise.

So the tells the client to forget the session id after an hour. What does the server do after an hour? Run this:

Try it

It prints True. Nothing in the server reads a clock, so the entry stays until someone logs out with that id. If nobody does, it stays for as long as the server runs. Max-Age is a request to the client. A client that kept a copy of the id, or an attacker who copied it once, can go on sending it, and the server still accepts it.

Two parts of the finding are given:

  • Exposed: a logged-in session, for as long as the server runs.

  • Attack: a session id that was ever copied keeps working. Max-Age asks the client to forget, and the server never does.

The server never ends a session by time. Which pair completes the finding?

Your turn

The last one is the cookie itself. This is the whole :

def session_cookie(session_id, *, max_age=SESSION_AGE):
    """Return the Set-Cookie value that hands session_id to the client."""
    cookie = http.cookies.SimpleCookie()
    cookie["session"] = session_id
    cookie["session"]["httponly"] = True
    cookie["session"]["path"] = "/"
    cookie["session"]["max-age"] = max_age
    return cookie["session"].OutputString()

For the id abc it returns session=abc; HttpOnly; Max-Age=3600; Path=/. with Python described each attribute as a request to the client. This cookie makes three requests: keep me away from page scripts, send me with every path, forget me in an hour.

A cookie can say two more things, and this one says neither. Secure means: send me over HTTPS only. SameSite means: do not send me with requests that start on another website. HTTP with Python named both, and you only need to recognize them today. Chapter 4 teaches both, and Chapter 8 shows what goes wrong without the second.

Here are four sentences from a finding about this cookie. Which one is its Attack?

The two drafts

Here are both findings as rows, in the layout SECURITY.md uses. The file calls the proof Test, because in this course a proof is always a test. Neither finding has one yet.

#ExposedAttackFixTest
F3A logged-in session, for as long as the server runsA session id that was ever copied keeps working: Max-Age asks the client to forget, and the server never doesRecord when a session started and was last used, and refuse and remove old onesnone yet
F4The session cookie, wherever a browser is willing to send itThe cookie carries HttpOnly, Max-Age, and Path only, so nothing tells a browser to keep it to HTTPS or to requests from this siteSet Secure and SameSite on purposenone yet

In the next lesson you copy these rows, or your own wording of them, into SECURITY.md.

Both rows end with “none yet”, and that is the weak spot of a finding on paper: it is a claim. The fourth part is what turns a claim into something a computer can check. The next lesson writes the first one, for a finding you have not seen yet.