Web Security Basics — XSS, CSRF, SQL Injection, and OWASP Top 10
Web security is the practice of protecting websites and web applications from attacks, data breaches, and unauthorized access — covering everything from secure communication to input validation and access control.
What You’ll Learn
- HTTPS, TLS/SSL, and secure communication
- Cross-Site Scripting (XSS) and how to prevent it
- Cross-Site Request Forgery (CSRF) protection
- SQL injection prevention techniques
- Content Security Policy (CSP) and secure headers
- OWASP Top 10 vulnerabilities overview
Why It Matters
Web attacks cost businesses trillions of dollars annually. A single vulnerability can expose millions of user records, destroy brand trust, and lead to regulatory fines. Every web developer must understand and prevent the most common security flaws — not just security specialists.
Real-world use: Durga Antivirus Pro actively scans web traffic for XSS and SQL injection attempts, blocking them before they reach the user. Doda Browser includes built-in protections against malicious sites and warns users about insecure connections.
flowchart LR
A[Input Validation] --> B[Output Encoding]
B --> C[CSP Headers]
C --> D[HTTPS/TLS]
D --> E[CSRF Tokens]
E --> F[Secure Authentication]
style A fill:#4af,color:#fff
style C fill:#f90,color:#fff
style D fill:#4a4,color:#fff
HTTPS and TLS/SSL
HTTPS encrypts all communication between the browser and server using TLS/SSL, preventing eavesdropping, tampering, and man-in-the-middle attacks.
Why HTTPS Matters
- Encryption — Data is unreadable to interceptors
- Integrity — Data can’t be modified in transit
- Authentication — Proves you’re talking to the real server
- Required for modern features — Service workers, geolocation, notifications, payment APIs
# Nginx HTTPS configuration
server {
listen 443 ssl http2;
server_name dodatech.com;
ssl_certificate /etc/ssl/certs/dodatech.crt;
ssl_certificate_key /etc/ssl/private/dodatech.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# HSTS — tell browsers to always use HTTPS
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
# Redirect HTTP to HTTPS
if ($scheme = http) {
return 301 https://$host$request_uri;
}
}Cross-Site Scripting (XSS)
XSS occurs when an attacker injects malicious scripts into web pages viewed by other users. There are three types:
Reflected XSS
The malicious script comes from the current HTTP request.
// VULNERABLE — reflects user input directly
app.get('/search', (req, res) => {
const query = req.query.q;
res.send(`<h1>Search results for: ${query}</h1>`); // XSS!
});
// Exploit: /search?q=<script>alert('xss')</script>
// FIXED — encode output
app.get('/search', (req, res) => {
const query = req.query.q;
const encoded = query.replace(/[&<>"']/g, function(m) {
return {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
}[m];
});
res.send(`<h1>Search results for: ${encoded}</h1>`);
});Stored XSS
The malicious script is stored on the server (database, comments, etc.) and served to other users.
// VULNERABLE — storing and displaying user comments without encoding
app.post('/comment', (req, res) => {
db.save({ text: req.body.comment }); // Stores <script> tags
});
app.get('/comments', (req, res) => {
const comments = db.getAll();
// Renders malicious scripts in all visitors' browsers
res.send(comments.map(c => `<div>${c.text}</div>`));
});
// FIXED — sanitize on input, encode on output
const sanitizeHtml = require('sanitize-html');
app.post('/comment', (req, res) => {
const clean = sanitizeHtml(req.body.comment, {
allowedTags: ['b', 'i', 'em', 'strong', 'a'],
allowedAttributes: { 'a': ['href'] }
});
db.save({ text: clean });
});DOM-based XSS
The vulnerability exists in client-side JavaScript rather than server-side HTML.
// VULNERABLE — reading from URL and writing to DOM
const param = new URLSearchParams(window.location.search).get('name');
document.getElementById('greeting').innerHTML = `Hello, ${param}`;
// Exploit: page.html?name=<img src=x onerror=alert(1)>
// FIXED — use textContent instead of innerHTML
document.getElementById('greeting').textContent = `Hello, ${param}`;Cross-Site Request Forgery (CSRF)
CSRF tricks authenticated users into performing unintended actions by sending forged requests from another site.
CSRF Protection with Tokens
// Server-side: generate and validate CSRF tokens
const crypto = require('crypto');
// On login, generate a CSRF token
function generateCsrfToken(userId) {
return crypto.randomBytes(32).toString('hex');
}
// In the form template
function renderForm(token) {
return `
<form action="/transfer" method="POST">
<input type="hidden" name="_csrf" value="${token}">
<input type="text" name="amount">
<input type="text" name="destination">
<button type="submit">Transfer</button>
</form>
`;
}
// Server-side validation
app.post('/transfer', (req, res) => {
const token = req.body._csrf;
const expected = getUserCsrfToken(req.userId);
if (!crypto.timingSafeEqual(Buffer.from(token), Buffer.from(expected))) {
return res.status(403).send('Invalid CSRF token');
}
// Process transfer...
});
// Modern approach: SameSite cookies
// Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly
CSRF Protection Headers
// Check custom headers for AJAX requests
app.post('/api/transfer', (req, res) => {
const origin = req.get('Origin');
const referer = req.get('Referer');
// Verify the request came from your site
if (origin && !origin.includes('yoursite.com')) {
return res.status(403).send('Forbidden');
}
// Process request...
});SQL Injection
SQL injection occurs when user input is included in SQL queries without proper sanitization, allowing attackers to read, modify, or delete database data.
// VULNERABLE — string concatenation in SQL
app.get('/user', (req, res) => {
const userId = req.query.id;
// ' OR '1'='1' -- deletes all users
const query = `SELECT * FROM users WHERE id = '${userId}'`;
db.query(query, (err, results) => {
res.json(results);
});
});
// FIXED — parameterized queries
app.get('/user', (req, res) => {
const userId = req.query.id;
const query = 'SELECT * FROM users WHERE id = $1';
db.query(query, [userId], (err, results) => {
res.json(results);
});
});ORM Protection
// Using an ORM (Object-Relational Mapper) also prevents SQL injection
// Example with Prisma
const user = await prisma.user.findUnique({
where: { id: parseInt(userId) }
});
// Example with Sequelize
const user = await User.findOne({
where: { id: userId }
});Content Security Policy (CSP)
CSP is a browser security mechanism that prevents XSS and data injection attacks by specifying which sources of content are allowed to load.
<!-- CSP via meta tag (limited) -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' https://analytics.example.com;
style-src 'self' 'unsafe-inline';
img-src 'self' https: data:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
form-action 'self';">
<!-- CSP via HTTP header (preferred) -->
<!-- Content-Security-Policy: ... --># Nginx CSP header
add_header Content-Security-Policy "
default-src 'self';
script-src 'self' https://www.google-analytics.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
" always;Secure HTTP Headers
# All security headers in one place
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header X-XSS-Protection "0" always; # Deprecated, use CSP
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(self)" always;
add_header Content-Security-Policy "default-src 'self'" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;OWASP Top 10
The OWASP Top 10 is the standard awareness document for web application security:
- Broken Access Control — Users can access resources they shouldn’t
- Cryptographic Failures — Weak encryption or sensitive data exposure
- Injection — SQL, NoSQL, OS command injection
- Insecure Design — Missing security controls in architecture
- Security Misconfiguration — Default passwords, unpatched systems
- Vulnerable Components — Outdated libraries with known CVEs
- Authentication Failures — Weak passwords, session fixation
- Data Integrity Failures — Deserialization attacks, unsafe updates
- Logging & Monitoring Failures — No visibility into attacks
- SSRF — Server-side request forgery
Common Errors
- Trusting user input — Never trust any input from users (forms, URLs, headers, cookies, files). Validate and sanitize everything.
- Storing passwords in plaintext — Always hash passwords with bcrypt, argon2, or PBKDF2. Never store raw passwords.
- Missing CSRF tokens — Every state-changing request (POST, PUT, DELETE) needs a CSRF token when using cookie-based auth.
- Default error messages — Don’t expose stack traces, SQL queries, or internal paths in error messages shown to users.
- Not updating dependencies — Regularly run
npm auditorpip auditand patch known vulnerabilities in libraries.
Practice Questions
What is the difference between XSS and CSRF? XSS injects malicious scripts that execute in a user’s browser. CSRF tricks authenticated users into performing unwanted actions on a trusted site. XSS can bypass CSRF protections.
How does a Content Security Policy (CSP) prevent XSS? CSP restricts which sources can load scripts, styles, and other resources. Even if an attacker injects
<script>, CSP blocks it unless it’s from an allowed source.Why are parameterized queries safe against SQL injection? Parameterized queries separate SQL logic from user data. The database treats parameters as data values, never as executable SQL, preventing injection.
What is the SameSite cookie attribute and how does it prevent CSRF?
SameSite=Strictprevents cookies from being sent with cross-site requests, stopping CSRF attacks entirely.SameSite=Laxallows top-level navigations with GET requests.What information does HTTPS encrypt? HTTPS encrypts the entire HTTP request/response — URL path, query parameters, headers, cookies, and body. It does NOT encrypt the domain name (visible in the TLS handshake) or IP address.
Challenge
Set up a local web server with all security headers properly configured. Create a page with a form that is vulnerable to stored XSS. Then fix it with proper output encoding and CSP headers. Verify both the vulnerable and fixed versions.
Real-World Task
Perform a security audit of a simple web application. Identify at least five vulnerabilities (XSS, CSRF, SQL injection, missing headers, weak password policy). Document each finding with its impact, reproduction steps, and fix. Use the audit report format that Durga Antivirus Pro uses for its security scanning service.
Related: HTTPS Guide | Related: OWASP Top 10 | Related: SQL Injection
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro