Secure by Default: XSS/CSRF/SQLi Crash Course for Coders — copy-paste sanitization & middleware.
Dive into this ultimate guide to web security fundamentals. From understanding the threats of Cross-Site Scripting (XSS), Cross-Site Request Forgery (CSRF), and SQL Injection (SQLi) to implementing copy-paste ready sanitization functions and middleware solutions. Designed for coders who want to secure their applications by default, with clear logic, real-world examples, and code in multiple languages like JavaScript, Python, and PHP.
Secure by Default: XSS/CSRF/SQLi Crash Course for Coders — copy‑paste sanitization & middleware.
```Safety note for this article: All potentially dangerous payloads are shown as escaped text inside blocks. There are no live
One‑off execution via crafted link.
Stored
Payload is saved in a database and served to other users.
Persistent impact across many views.
DOM‑based
Vulnerability exists purely in client‑side JS manipulating the DOM unsafely.
// avoid: document.write(location.hash)
Client‑side execution without server round‑trip.
Examples & gotchas
- Context matters: HTML text, attributes, JS strings, CSS, and URLs all require different escaping.
- Frameworks like React/Angular/Vue auto‑escape by default. Avoid raw HTML sinks (e.g.,
dangerouslySetInnerHTML,v-html). - Unicode/encoding tricks exist. Normalize to UTF‑8 and prefer vetted libraries.
Copy‑Paste Sanitization for XSS
Node.js (server‑side) using DOMPurify + JSDOM:
```
const DOMPurify = require('dompurify');
const { JSDOM } = require('jsdom');
const window = new JSDOM('').window;
const purify = DOMPurify(window);
function sanitizeHTML(input) {
if (typeof input !== 'string') return input;
return purify.sanitize(input, {
ALLOWED_TAGS: ['p','b','i','em','strong','ul','ol','li','code','pre','a'],
ALLOWED_ATTR: { a: ['href','rel','target'] }
});
}
```
Python (Flask) using markupsafe / bleach:
```
from markupsafe import escape
from flask import Flask, request
import bleach
app = Flask(__name__)
ALLOWED_TAGS = ['p','b','i','em','strong','ul','ol','li','code','pre','a']
ALLOWED_ATTRS = { 'a': ['href','rel','target'] }
def sanitize_rich(text: str) -> str:
return bleach.clean(text or '', tags=ALLOWED_TAGS, attributes=ALLOWED_ATTRS)
@app.route('/search')
def search():
q = request.args.get('q','')
# Plain text context:
return f"You searched for: {escape(q)}"
```
PHP: use context‑aware escaping when outputting untrusted data.
```
```
Middleware for XSS Protection
Express.js — global headers + on‑write sanitization:
```
const express = require('express');
const helmet = require('helmet');
const app = express();
app.use(express.json());
app.use(helmet({ contentSecurityPolicy: { useDefaults: true } }));
app.use((req, res, next) => {
if (req.body && typeof req.body === 'object') {
for (const k of Object.keys(req.body)) {
req.body[k] = sanitizeHTML(req.body[k]);
}
}
next();
});
```
CodeIgniter 4 — enable the built‑in ContentSecurityPolicy filter and set auto‑escape in views:
```
// app/Config/Filters.php
public $globals = [
'before' => ['csrf'],
'after' => ['toolbar', 'csp'],
];
// In your views, use esc() for variables:
```
Demystifying CSRF Attacks
What is CSRF?
CSRF abuses the browser’s automatic credential sending (cookies, HTTP auth) to submit unintended state‑changing requests on behalf of an authenticated user.
CSRF Attack Scenarios (escaped)
Escaped example of an auto‑submitting form (do not run as live HTML):
```
```
Tokens & Cookie Defenses
- Include a unique, unpredictable token with each state‑changing request and verify it server‑side.
- Set session cookies with
SameSite=Lax(orStrictif UX allows),HttpOnly, andSecure. - Validate
Origin/Refererheaders where feasible.
Express + csurf (cookie‑based tokens):
```
const csurf = require('csurf');
const cookieParser = require('cookie-parser');
app.use(cookieParser());
app.use(csurf({ cookie: true }));
app.get('/form', (req, res) => {
res.render('form', { csrfToken: req.csrfToken() });
});
```
Flask (custom):
```
import secrets
from flask import session, request, abort
def get_csrf_token():
session.setdefault('csrf', secrets.token_urlsafe(32))
return session['csrf']
def require_csrf():
token = request.form.get('csrf') or request.headers.get('X-CSRF-Token')
if not token or token != session.get('csrf'):
abort(403)
```
Django: enable CsrfViewMiddleware and add {% csrf_token %} in forms (on by default in new projects).
CSRF Middleware Implementation
Apply tokens globally to all non‑idempotent methods (POST/PUT/PATCH/DELETE). For APIs used by SPAs or mobile apps, send the token in a custom header.
SQL Injection: The Silent Killer
What is SQLi?
SQLi occurs when user input is concatenated into SQL, altering query structure. The defense is simple: parameterized queries everywhere, every time.
Types of SQL Injection
| Type | Description | Escaped Example | Primary Defense |
|---|---|---|---|
| In‑band (Union/Error) | Data returned in the same response. | ' UNION SELECT username,password FROM users -- |
Prepared statements. |
| Blind | Infer via booleans or time delays. | AND 1=1 /* or SLEEP(5) */ |
Input validation + params. |
| Out‑of‑band | Exfiltration via a separate channel. | LOAD_FILE(...) INTO OUTFILE ... |
Least privilege DB user. |
SQLi Exploitation Examples (escaped)
Vulnerable pattern (do not use):
```
// ❌ Vulnerable PHP (example only)
// $id = $_GET['id'];
// $sql = "SELECT * FROM users WHERE id = '$id'";
```
Safe patterns:
```
// PHP (PDO)
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_GET['id']]);
$rows = $stmt->fetchAll();
// Node (mysql2)
const [rows] = await conn.execute('SELECT * FROM users WHERE id = ?', [id]);
// Python (sqlite3)
cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
```
Prepared Statements & Validation
- Always bind parameters; never concatenate.
- Whitelist expected formats (e.g.,
is_intfor IDs; enum checks for status fields). - Use ORM layers (SQLAlchemy, Sequelize, Eloquent) which parametrize by default.
- Limit DB privileges for the app user (avoid
DROP/ALTER).
Middleware & WAF Patterns
Middleware can enforce schema validation at the edge. A WAF (e.g., ModSecurity/OWASP CRS) can provide an additional safety net for obvious injection patterns.
```
// Express + express-validator
const { body } = require('express-validator');
app.post('/user', [ body('id').isInt(), body('name').trim().escape() ], handler);
```
Best Practices & Secure Coding Habits
- Least privilege: restrict DB and filesystem permissions.
- Defense in depth: combine escaping, CSP, CSRF tokens, and parameterized queries.
- Secure headers: use HSTS, CSP, X‑Content‑Type‑Options, Referrer‑Policy.
- Logging & monitoring: centralize logs; alert on anomalies.
- Patch management: keep dependencies up to date (npm audit, pip‑audit, composer audit).
- Reviews & tests: threat‑model, code review checklists, and automated security scans.
| Checklist | XSS | CSRF | SQLi |
|---|---|---|---|
| Input validation | Context‑aware escaping | Token present/verified | Params used everywhere |
| Middleware/filters | CSP + sanitizers | Global token enforcement | Schema/validators |
| Testing | ZAP active scan | Origin/Referer checks | sqlmap on dev |
Tools & Testing Strategies
- Static: ESLint Plugin Security, Bandit (Python), Psalm (PHP).
- Dynamic: OWASP ZAP, Burp Suite Community/Pro, sqlmap (dev only).
- CI/CD: include security linters and dependency audits in pipelines.
Additional Resources
- OWASP Cheat Sheet Series: XSS, CSRF, SQL Injection
- PortSwigger Web Security Academy labs
- OWASP ModSecurity Core Rule Set (CRS)
This is a clean, production‑safe version with all live payloads removed or escaped, generic domains (example.com) only, and no external calls.
```
What's Your Reaction?
Like
0
Dislike
0
Love
0
Funny
0
Angry
0
Sad
0
Wow
0