Web & Frontend Security
The browser runs our code on a stranger's machine, next to other tabs, extensions, and scripts that may be hostile. Web security is about making sure the page cannot be tricked into running an attacker's code, leaking a user's session, or acting on a forged request. Most of it comes from a few well-understood defences applied consistently.
The classic web attacks have names and known fixes. Cross-site scripting (XSS) injects script into a page. Cross-site request forgery (CSRF) makes the user's browser send an action they did not intend. Clickjacking tricks clicks through an invisible frame. And some attacks leak tokens or data the page should not expose. The frontend is never the security boundary. The server must re-check everything (see Authentication & Authorization).
If you are newer to this, the short version is: let the framework escape output, never build HTML from untrusted strings, keep tokens out of places scripts can read, and set the standard security headers. Do those, and you have closed the doors most attacks use.
Stop injection and code execution
- AlwaysLet the framework escape output by default (React/Razor escape text). Render untrusted data as text, never as raw HTML.
- DoSet a Content-Security-Policy (CSP) to restrict where scripts, styles, and frames can come from. It is a strong second line if an injection slips through.
- DoValidate and sanitise any rich content (HTML you must render) with a trusted, maintained sanitiser. Never use your own regex.
- AvoidBuilding markup or DOM by joining strings of user input. Prefer framework binding that escapes for you.
- NeverPass untrusted content to
dangerouslySetInnerHTML,innerHTML, or an equivalent without sanitising it first. That is a direct XSS hole.
Protect sessions, requests, and the page
- DoStore session tokens in HttpOnly, Secure, SameSite cookies. Keep auth tokens out of
localStorage/sessionStorage, where any script can read them (see Session & Token Management). - DoProtect state-changing requests against CSRF (anti-forgery tokens and/or SameSite cookies), so another site cannot act as the user.
- DoSend the baseline security headers: CSP, HSTS, X-Content-Type-Options, and frame-ancestors/X-Frame-Options to prevent clickjacking (see Secure Defaults).
- DoUse Subresource Integrity (SRI) and trusted sources for any third-party scripts you must include.
- AlwaysEnforce every authorisation and validation rule on the server. The client is for convenience and UX, never for security. Hiding a button is not access control.
- NeverPut secrets, API keys, or other users' data into client-side code or the page. Anything the browser receives, the user — and an attacker — can read.
localStorage.setItem('jwt', token); // any XSS can steal this
If a single XSS bug ever lands, the attacker reads the token straight out of localStorage and becomes the user. Use an HttpOnly cookie the script cannot read instead.
// server sets: Set-Cookie: session=...; HttpOnly; Secure; SameSite=Lax
// page sends: Content-Security-Policy: default-src 'self'
The token is invisible to JavaScript, and CSP stops injected scripts from running even if some untrusted content slips in.
Self-review checklist
- AskIs any untrusted data rendered as HTML instead of escaped text?
- AskCan a script on the page read the session token?
- AskCould another website trigger a state-changing action as the logged-in user (CSRF)?
- AskAm I relying on the client for any check the server must enforce?