Phase 00 ยท Foundations ยท Lesson 7

The web stack

The web is where most real attacks happen, because it is the part of every organisation deliberately exposed to the whole internet. This lesson takes the machine apart so Phase 02 has something to work on.

โฑ 30 minutes ๐Ÿ“Š Builds on lesson 00.4 ๐Ÿงช Browser dev tools

01 Client and server, and who you can trust

Every web interaction has two halves. The client is your browser, running on your machine. The server is someone else's computer, running their code.

The split matters enormously, and it produces the single most important rule in web security.

Client (your browser) HTML, CSS, JavaScript. Fully under the user's control. Every value here can be changed by whoever is sitting at the keyboard.
โŸท the network โŸท HTTP requests and responses. Interceptable and editable in transit.
Server (their machine) Application code and the database. The only place a security decision can actually be enforced.
๐Ÿšจ
Never trust the client

Anything the browser sends can be altered before it arrives. Hidden form fields, prices, user IDs, JavaScript validation, disabled buttons, all of it. If a check happens only in the browser, it is not a security control, it is a suggestion. This one sentence explains a large fraction of the vulnerabilities you will find in Phase 02.4.

02 The three languages in every page

You do not need to build websites. You need to recognise what each part does, because attacks target them differently.

LanguageJobWhy an attacker cares
HTMLStructure and contentForms and inputs are where user data enters the system
CSSAppearanceCan hide elements or overlay invisible ones for clickjacking
JavaScriptBehaviour in the browserIf an attacker runs their JavaScript in your browser, they act as you

That last row is cross-site scripting, usually written XSS, and it is one of the most common web vulnerabilities in the world. The attacker's goal is to get their JavaScript to run inside someone else's session, at which point they can read the page, submit forms, and steal the session token.

03 The anatomy of a request

Lesson 00.4 showed you a request in outline. Now look at the parts properly.

POST /login HTTP/1.1
Host: shop.example.com
User-Agent: Mozilla/5.0
Cookie: session=a3f9b2c8d1
Content-Type: application/x-www-form-urlencoded

username=alice&password=hunter2

Four things are worth naming, because you will manipulate all of them later.

  • The method says what kind of action this is. GET asks for something, POST submits something. Others exist, including PUT and DELETE.
  • The path says which resource is wanted. Attackers manipulate this to reach things they should not, which is called path traversal.
  • The headers carry metadata, including the all-important cookie.
  • The body carries submitted data, here the login form.
๐Ÿ”Ž
GET versus POST, and why it matters

A GET puts its data in the URL, which means it lands in browser history, server logs and referrer headers. A POST puts it in the body, which is not logged by default. This is why a password must never travel in a URL. It is not about encryption, since both are encrypted equally under HTTPS. It is about where the data gets written down afterwards.

Check yourself

A site sends a password reset token in the URL, like /reset?token=abc123. What is the risk?

HTTPS does protect the URL in transit, so the wire is fine. The problem is everywhere the URL gets written down at both ends: the user's history, the server's access logs, and the referrer header sent to any third-party resource the page loads. A secret that ends up in a log file is no longer a secret.

Send some requests and read the replies. Notice how much a status code gives away.

04 Sessions: how a website remembers you

HTTP is stateless. Each request arrives with no memory of the last one. The server genuinely does not know that the request asking for your inbox came from the same person who logged in a moment ago.

Cookies solve this. When you log in successfully, the server generates a random session identifier, stores it, and sends it back. Your browser then attaches it to every subsequent request automatically.

Browser Server POST /login username + password Set-Cookie: session=a3f9b2c8 GET /inbox Cookie: session=a3f9b2c8 the browser stores it and now sends it automatically no password needed, the token alone proves identity

the session token replaces the password on every later request

Notice what that means. After login, the token is the identity. Anyone holding it is you, as far as the server is concerned. No password required, and in most cases no second factor either.

The flags that protect a cookie

FlagWhat it doesWhat it prevents
HttpOnlyJavaScript cannot read the cookieCross-site scripting stealing the session
SecureOnly ever sent over HTTPSLeaking the token over plain HTTP
SameSiteNot sent on requests from other sitesCross-site request forgery

A missing flag on a session cookie is a genuine, reportable finding on a penetration test. You will check for exactly this in Phase 02.4.

Check yourself

Why does the HttpOnly flag matter so much when a site has a cross-site scripting flaw?

HttpOnly does not fix the underlying vulnerability, and the attacker's script still executes. What it removes is the most valuable prize. This is defence in depth: assume one control will fail, and make sure the failure is not catastrophic on its own.

05 The same-origin policy

Here is the rule that stops the web from being completely broken. A page from one origin cannot read data from a different origin.

An origin is the combination of scheme, domain and port. All three must match.

Compared with https://shop.com/pageSame origin?Why
https://shop.com/otherYesOnly the path differs, which does not matter
http://shop.com/pageNoDifferent scheme
https://mail.shop.com/pageNoDifferent subdomain is a different domain
https://shop.com:8443/pageNoDifferent port

Without this rule, a malicious page you opened in one tab could quietly read your bank account in another. The same-origin policy is why it cannot.

๐ŸŒ
CORS is the deliberate exception

Sometimes a site genuinely needs to let another origin read its data, for example an API serving a front end on a different domain. Cross-Origin Resource Sharing is the mechanism for granting that, using response headers. Misconfigured CORS that permits any origin is a common and serious finding, because it hands away the protection the same-origin policy provides.

06 APIs, where the real data lives

Modern sites often serve a nearly empty page and then fetch the actual data separately, as JSON, from an API. That means the interesting traffic is frequently invisible in the page source and only shows up in the network panel.

GET /api/v1/users/1042/orders HTTP/1.1
Host: shop.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

Look at that path. It contains 1042, a user ID. The obvious question, and it is the right question, is what happens if you change it to 1043.

If the server returns someone else's orders, that is insecure direct object reference, usually shortened to IDOR. It is one of the most common and most damaging web flaws precisely because it is so simple. The server authenticated you, but forgot to check whether you are authorised for this specific record.

๐Ÿ”‘
Authentication is not authorisation

Proving who you are and being allowed to see a particular thing are two separate checks. IDOR happens when a developer does the first and forgets the second. You will exploit this in Phase 02.4 and it is covered from the defensive side in lesson 01.3.

07 Do it on your real machine

Your browser contains a full inspection toolkit. Open developer tools in Safari or Chrome with Command + Option + I. In Safari you may first need to enable the Develop menu in Settings under Advanced.

Try this on this very page, which is served from your own machine so there is nothing to worry about:

  1. Open the Network tab, then reload. Every file the page requested is listed, with its status code and size.
  2. Click any request and look at the headers, matching them to section 03 above.
  3. Open the Console tab and type document.title, then press Enter. You just ran JavaScript inside the page, which is exactly what an XSS attacker wants to achieve.
  4. Open the Storage or Application tab and find Local Storage. Your lesson progress is stored there.

Now from the terminal. Fetch only the response headers:

curl -I https://example.com

See the full request and response including the TLS negotiation:

curl -v https://example.com -o /dev/null

Send a request with a custom header, the way a tool would:

curl -H "User-Agent: MidorCyber-Learning" -I https://example.com

Fetch some JSON from a public test API and look at the structure:

curl -s https://api.github.com/zen
โš–๏ธ
Still the same rule

Requesting a public page or a public API is ordinary internet use. Changing an ID in someone else's URL to see another person's data is unauthorised access, even when it is trivially easy and even if you report it afterwards. Practise IDOR on the deliberately vulnerable applications you will set up in lesson 00.8, never on a live site.

Your checklist

  • Can explain why client-side checks are not security controls
  • Can name the four parts of an HTTP request
  • Understand why a secret in a URL leaks even under HTTPS
  • Know what the HttpOnly, Secure and SameSite flags each prevent
  • Can decide whether two URLs share an origin
  • Opened dev tools and inspected the network panel on this page
  • Ran JavaScript in the console and saw local storage
  • Can describe IDOR in one sentence

08 Final check

Question 1 of 3

A shopping site validates the price in JavaScript before submitting the order. Why is that insufficient?

The client is the attacker's territory. They can edit the JavaScript, disable it, or skip the page entirely and send a crafted request with a tool. HTTPS does not help at all, because it protects the message in transit from third parties, not from the person who composed it. The server must re-check the price against its own records.

Question 2 of 3

You are logged into your bank in one tab and open a malicious page in another. What stops that page from reading your bank balance?

The same-origin policy is the browser rule doing this work. The certificate proves you reached the real bank, but does nothing about other tabs. HttpOnly stops scripts on the bank's own page from reading the cookie, which is a different protection against a different attack.

Question 3 of 3

An API returns your profile at /api/users/1042. Changing it to 1043 returns another user's profile. What is the flaw?

This is IDOR. The server correctly authenticated you, then failed to check whether you are permitted to view record 1043 specifically. Nothing was injected and nothing was intercepted. The whole flaw is a missing ownership check, which is why it slips through code review so often.
๐ŸŽ“
What you now know

The client is untrusted territory and only the server can enforce a rule. A request is a method, a path, headers and a body. Sessions turn a token into your identity, which is why cookie flags matter. The same-origin policy keeps tabs apart. And authentication without authorisation produces IDOR. Phase 02.4 attacks every one of these.

Key takeaways

The things from this lesson worth carrying into the next one. If you remember nothing else, remember these.

Carry these forward

  1. The user owns the client and can edit it, disable it, or skip the page and send a crafted request. Only the server can enforce a rule.
  2. HttpOnly stops JavaScript reading the cookie, so XSS cannot steal the session. Secure sends it only over HTTPS. SameSite blocks cross-site request forgery.
  3. It stops one page reading another origin's data. An origin is scheme, domain and port, and all three must match, so http differs from https and subdomains differ.
  4. Insecure direct object reference, an authorisation failure. The server authenticated you correctly but never checked that you may see that specific record.

Keep going

You have read it and tried it in the lesson. Now cement it. These three do more for retention than re-reading ever will.