Skip to content
All essays
WebFebruary 4, 202514 min

Web Security Best Practices 2025: Modern Application Security

Comprehensive guide to web application security. Learn about HTTPS, headers, CSP, XSS protection, and modern security practices.

Ü
Ümit Uz
Mobile & Full Stack Developer

HTTPS Everywhere

SSL/TLS Configuration

nginx
server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
}

server {
    listen 80;
    server_name example.com;
    return 301 https://$server_name$request_uri;
}

Certificate Management

bash
# Let's Encrypt
certbot --nginx -d example.com -d www.example.com

# Auto-renewal
certbot renew --dry-run

Security Headers

Essential Headers

javascript
// Express.js
import helmet from 'helmet';

app.use(helmet());

// Custom headers
app.use((req, res, next) => {
  res.setHeader('X-Frame-Options', 'DENY');
  res.setHeader('X-Content-Type-Options', 'nosniff');
  res.setHeader('X-XSS-Protection', '1; mode=block');
  res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
  res.setHeader('Permissions-Policy', 'geolocation=(), microphone=()');
  next();
});

Content Security Policy

javascript
app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'"],
    styleSrc: ["'self'", "'unsafe-inline'"],
    scriptSrc: ["'self'"],
    imgSrc: ["'self'", 'data:', 'https:'],
    connectSrc: ["'self'"],
    fontSrc: ["'self'"],
    objectSrc: ["'none'"],
    mediaSrc: ["'self'"],
    frameSrc: ["'none'"],
  },
}));

XSS Protection

Input Sanitization

javascript
import DOMPurify from 'dompurify';

// Sanitize HTML
const clean = DOMPurify.sanitize(dirtyInput);

// React (automatic by default)
<div>{userInput}</div> // Safe

// Dangerously set innerHTML (dangerous)
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(dirtyInput) }} />

Output Encoding

javascript
// Encode output
import he from 'he';

const encoded = he.encode('<script>alert("XSS")</script>');
// &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;

SQL Injection Prevention

Parameterized Queries

javascript
// Bad - Vulnerable
const query = `SELECT * FROM users WHERE id = '${userId}'`;

// Good - Parameterized
const query = 'SELECT * FROM users WHERE id = ?';
db.query(query, [userId]);

// Best - ORM
const user = await User.findByPk(userId);

ORM Protection

javascript
// Sequelize
const users = await User.findAll({
  where: {
    status: 'active'
  }
});

// Prisma
const users = await prisma.user.findMany({
  where: { status: 'active' }
});

Authentication Security

Password Hashing

javascript
import bcrypt from 'bcrypt';

// Hash password
const hashedPassword = await bcrypt.hash(password, 10);

// Verify password
const isValid = await bcrypt.compare(password, hashedPassword);

Session Management

javascript
// Secure cookie configuration
app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  cookie: {
    secure: true, // HTTPS only
    httpOnly: true, // Prevent XSS
    maxAge: 3600000, // 1 hour
    sameSite: 'strict', // CSRF protection
  }
}));

JWT Security

Token Structure

javascript
import jwt from 'jsonwebtoken';

// Create token
const token = jwt.sign(
  { userId: user.id },
  process.env.JWT_SECRET,
  { expiresIn: '1h' }
);

// Verify token
const decoded = jwt.verify(token, process.env.JWT_SECRET);

Best Practices

  1. 1Use strong secrets: At least 32 characters
  2. 2Short expiration: 15 minutes to 1 hour
  3. 3Refresh tokens: Long-lived refresh tokens
  4. 4HTTPS only: Never transmit over HTTP
  5. 5Store securely: httpOnly cookies

CSRF Protection

CSRF Tokens

javascript
import csrf from 'csurf';

const csrfProtection = csrf({ cookie: true });

app.use(csrfProtection);

app.get('/form', (req, res) => {
  res.render('form', { csrfToken: req.csrfToken() });
});

app.post('/form', csrfProtection, (req, res) => {
  // Process form
});

SameSite Cookies

javascript
app.use(session({
  cookie: {
    sameSite: 'strict', // or 'lax'
    secure: true,
  }
}));

Rate Limiting

Express Rate Limit

javascript
import rateLimit from 'express-rate-limit';

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // 100 requests per windowMs
  message: 'Too many requests',
});

app.use('/api/', limiter);

Data Validation

Input Validation

javascript
import { body, validationResult } from 'express-validator';

app.post('/api/users', [
  body('email').isEmail().normalizeEmail(),
  body('password').isLength({ min: 8 }),
  body('age').isInt({ min: 18, max: 120 }),
], (req, res) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(400).json({ errors: errors.array() });
  }
  // Process request
});

File Upload Security

Validation

javascript
import multer from 'multer';

const upload = multer({
  dest: 'uploads/',
  limits: { fileSize: 5 * 1024 * 1024 }, // 5MB
  fileFilter: (req, file, cb) => {
    const allowedTypes = ['image/jpeg', 'image/png'];
    if (allowedTypes.includes(file.mimetype)) {
      cb(null, true);
    } else {
      cb(new Error('Invalid file type'));
    }
  }
});

Dependency Security

Audit Dependencies

bash
# Check for vulnerabilities
npm audit

# Fix vulnerabilities
npm audit fix

# Automated scanning
npm install -g npm-check-updates
ncu

Logging & Monitoring

Security Events

javascript
// Log security events
app.use((req, res, next) => {
  if (req.body.password) {
    logger.warn('Password in request', {
      ip: req.ip,
      path: req.path,
    });
  }
  next();
});

// Failed login attempts
if (!isValid) {
  logger.warn('Failed login attempt', {
    email: req.body.email,
    ip: req.ip,
  });
}

Best Practices Summary

  1. 1Always use HTTPS: No exceptions
  2. 2Validate all input: Never trust user input
  3. 3Use parameterized queries: Prevent SQL injection
  4. 4Implement rate limiting: Prevent brute force
  5. 5Keep dependencies updated: Security patches
  6. 6Use security headers: Extra protection layer
  7. 7Log security events: Monitor for attacks
  8. 8Regular security audits: Stay proactive

Conclusion

Web security is ongoing. Stay updated with latest threats and implement defense in depth.

Related essays

Next essay
React Native Deployment: App Store & Play Store