What it means for a web client
Start with the trust boundary. The client is untrusted: anyone can open DevTools and change any HTML, CSS or JavaScript you sent. The network is hostile unless HTTPS encrypts it. The server is the only place you control, so it is where validation, authorization and business logic must live. You validate on the client for usability and on the server for security. A maxlength, a readonly or an <input type="hidden"> is a convenience for honest users, not a lock.
Inside the browser, the unit of trust is the origin: scheme, host and port. Two pieces of content share trust if and only if they share an origin. The same-origin policy is precise about what it stops. A page may send a request to another origin and may embed another origin's images, frames and fonts, but it may not read the response or inspect what it embedded. CORS is the opt-in by which the owner of the data lets another origin read it.
The dangerous exception is the script. A <script src> from any server runs inside your origin with every power your own code has. It can read the DOM, read what the user types, read localStorage, and send all of it somewhere else. Cross-site scripting (XSS) is the same exception turned against you: an attacker's markup reaches the HTML parser, and the script it carries is trusted because it is in your origin, not because it is trustworthy. The same-origin policy guards the door between origins. It cannot help with code you carried inside.
So the defenses are layered, and each assumes the others may fail: TLS against eavesdropping and tampering in transit; the same-origin policy and CORS against cross-origin data theft; Content Security Policy and Subresource Integrity against injected or altered code; HttpOnly, Secure and SameSite cookies against stolen sessions and forged requests; the sandbox and Site Isolation underneath, containing a breach to one site. Most of these are things you declare in a header or an attribute, and the browser enforces what you declared.
Where it lives in each layer
- Structure
- URLs are user-controllable input. Every part of one can be edited, so a query parameter such as
?role=adminor?user_id=1proves nothing until the server checks authority. A user-supplied URL dropped into anhrefcan carry thejavascript:scheme; accept onlyhttp:andhttps:. A form that sends a password with GET puts it in the address bar, the history, the server logs and theRefererheader. Every element that names another server,<script>above all, is a trust decision made in markup. - Presentation
- A script that can draw on your page can draw over it, and a value dropped into a
styleattribute can load a URL or lay a transparent element across the page. Clickjacking is the same idea from outside: your real page, framed invisibly under someone else's bait. The answer is to say who may frame you, with theframe-ancestorsdirective of Content Security Policy. - Interaction
- This is where XSS gets written.
textContentwrites characters and never invokes the HTML parser;innerHTML,outerHTML,insertAdjacentHTMLandsrcdocall parse. UsetextContentfor every value that came from outside your code, and parse URLs before assigning them tohreforsrc. A component that takes rich content through an attribute and renders it withinnerHTMLhas the same hole; slots do not. - Delivery
- A response body is input from outside your program, even from your own endpoint, because that endpoint stores what somebody typed. A blocked cross-origin read tells your code nothing beyond
TypeError, and the request usually reached the server anyway. Credentialed requests, preflights and same-origin proxies each change what you are trusting. The headers that carry the defenses, fromContent-Security-PolicytoSet-Cookieflags, travel here too.
Where the course teaches it
- The Browser for Programmers, VII. The security model: the origin, the same-origin policy, CORS, cookie flags, XSS, CSRF, clickjacking and defense in depth. Start here.
- The Browser for Programmers, I. The browser as operating system: the sandbox and Site Isolation beneath everything else.
- The Browser for Programmers, II. From URL to first byte: the TLS handshake on the way to every HTTPS response.
- Foundations, section 16: Client-side security is an illusion: hidden fields, decorative restrictions, and the third-party script that reads your storage.
- Foundations, section 11: Client-server trade-offs: the trust boundary and where validation has to run.
- URLs, section 12: URL security: parameter tampering, open redirects, the
javascript:scheme and lookalike domains. - The DOM, V. Modification: why
innerHTMLplus user input is a code-injection hole. - Web Components, VI. Slots and templates: why rich content belongs in a slot, not an attribute.
- Client-Side Communication, 07. When it goes wrong: never trust the response, and what
textContentdoes not cover. - Client-Side Communication, 08. Other people's data: CORS as your code experiences it, credentials, and proxies.
- Everything You Embed (film): the keylogger, the hostile overlay, and the CSP header and integrity hash that answer them.
- The Localhost Effect (film): why the client is the place you cannot truly secure.
- URL Explorer: the URL Security tab, with lookalike domains, query-string mischief and misleading redirects.
Check your own page
- Search your JavaScript for
innerHTML,insertAdjacentHTMLandouterHTML. For each one, trace where the string came from. If any part came from a form, a URL or a response, switch totextContentor build the nodes yourself. - List every
<script src>that points at another server. For each, say why you trust that organization with your whole page, and add anintegrityhash withcrossoriginor remove it. - Open DevTools, delete a
required, raise amaxlengthand edit a hidden field, then submit. Whatever reaches the server is what an attacker can send. - Check every form that carries a password or personal data: it must use POST, and the page must be served over HTTPS.
- Open Application, then Cookies, and read the
HttpOnly,SecureandSameSitecolumns for anything that holds a session. - Look at your response headers in the Network panel. If there is no
Content-Security-Policy, write down whatscript-srcandconnect-srcwould have to allow, and notice what that list tells you about your page.
