As a best-selling author, I invite you to explore my books on Amazon. Don't forget to follow me on Medium and show your support. Thank you! Your support means the world!
I have been implementing web security measures for frontend applications throughout my career, and the threat landscape continues to evolve rapidly. Modern applications require comprehensive security strategies that address both traditional vulnerabilities and emerging attack vectors.
Content Security Policy Implementation
Content Security Policy serves as the first line of defense against cross-site scripting attacks. I implement CSP headers to control which resources browsers can load and execute. The policy defines trusted sources for scripts, stylesheets, images, and other content types.
// Comprehensive CSP configuration for Express.js
const helmet = require('helmet');
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'nonce-${nonce}'", "https://trusted-cdn.com"],
styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
imgSrc: ["'self'", "data:", "https:"],
connectSrc: ["'self'", "https://api.myapp.com"],
fontSrc: ["'self'", "https://fonts.gstatic.com"],
objectSrc: ["'none'"],
mediaSrc: ["'self'"],
frameSrc: ["'none'"]
}
}
}));
// Generate nonce for inline scripts
const crypto = require('crypto');
const generateNonce = () => crypto.randomBytes(16).toString('hex');
// Middleware to add nonce to response locals
app.use((req, res, next) => {
res.locals.nonce = generateNonce();
next();
});
I configure CSP to reject inline scripts by default, requiring nonce values for legitimate inline code. This approach prevents malicious script injection while maintaining functionality for necessary inline scripts.
<!-- HTML template with nonce implementation -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Secure Application</title>
<script nonce="<%= nonce %>" src="/js/bootstrap.js"></script>
</head>
<body>
<!-- Content -->
<script nonce="<%= nonce %>">
// Legitimate inline script with nonce
window.appConfig = {
apiUrl: '<%= apiUrl %>',
version: '<%= version %>'
};
</script>
</body>
</html>
Input Sanitization and Validation
I implement multiple layers of input validation to prevent malicious data from compromising applications. Client-side validation provides immediate user feedback, while server-side validation ensures security cannot be bypassed.
// Client-side input sanitization
class InputSanitizer {
static sanitizeHTML(input) {
const div = document.createElement('div');
div.textContent = input;
return div.innerHTML;
}
static validateEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email) && email.length <= 254;
}
static sanitizeUserInput(input, maxLength = 1000) {
if (typeof input !== 'string') return '';
return input
.trim()
.slice(0, maxLength)
.replace(/[<>]/g, '') // Remove potential script tags
.replace(/javascript:/gi, '') // Remove javascript: protocols
.replace(/on\w+=/gi, ''); // Remove event handlers
}
}
// Form validation implementation
document.getElementById('userForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
const sanitizedData = {};
for (let [key, value] of formData.entries()) {
sanitizedData[key] = InputSanitizer.sanitizeUserInput(value);
}
if (InputSanitizer.validateEmail(sanitizedData.email)) {
submitForm(sanitizedData);
} else {
showError('Please enter a valid email address');
}
});
Server-side validation provides the final security checkpoint. I use established libraries for input sanitization and implement strict validation rules for all user inputs.
// Server-side input validation with express-validator
const { body, validationResult } = require('express-validator');
const DOMPurify = require('isomorphic-dompurify');
const validateUserInput = [
body('email')
.isEmail()
.normalizeEmail()
.isLength({ max: 254 }),
body('name')
.trim()
.isLength({ min: 1, max: 100 })
.matches(/^[a-zA-Z\s]+$/)
.withMessage('Name can only contain letters and spaces'),
body('message')
.trim()
.isLength({ min: 1, max: 2000 })
.customSanitizer(value => DOMPurify.sanitize(value))
];
app.post('/submit', validateUserInput, (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Process sanitized input
const { email, name, message } = req.body;
// Save to database or process further
});
Secure Authentication Patterns
I implement authentication systems that protect user credentials through proper token handling and secure storage mechanisms. The approach uses httpOnly cookies for refresh tokens and secure client-side storage for access tokens.
// JWT authentication implementation
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
class AuthService {
static generateTokens(userId) {
const accessToken = jwt.sign(
{ userId, type: 'access' },
process.env.JWT_ACCESS_SECRET,
{ expiresIn: '15m' }
);
const refreshToken = jwt.sign(
{ userId, type: 'refresh' },
process.env.JWT_REFRESH_SECRET,
{ expiresIn: '7d' }
);
return { accessToken, refreshToken };
}
static async login(email, password) {
const user = await User.findByEmail(email);
if (!user || !await bcrypt.compare(password, user.passwordHash)) {
throw new Error('Invalid credentials');
}
const { accessToken, refreshToken } = this.generateTokens(user.id);
// Store refresh token in httpOnly cookie
return {
accessToken,
refreshToken,
user: {
id: user.id,
email: user.email,
name: user.name
}
};
}
}
// Login endpoint
app.post('/auth/login', async (req, res) => {
try {
const { email, password } = req.body;
const result = await AuthService.login(email, password);
// Set httpOnly cookie for refresh token
res.cookie('refreshToken', result.refreshToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict',
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days
});
res.json({
accessToken: result.accessToken,
user: result.user
});
} catch (error) {
res.status(401).json({ error: error.message });
}
});
Client-side token management requires careful handling to prevent XSS attacks from accessing authentication tokens.
// Secure client-side authentication manager
class AuthManager {
constructor() {
this.accessToken = null;
this.refreshPromise = null;
}
setAccessToken(token) {
this.accessToken = token;
// Store in memory only, not localStorage
}
async makeAuthenticatedRequest(url, options = {}) {
if (!this.accessToken) {
throw new Error('No access token available');
}
const response = await fetch(url, {
...options,
headers: {
...options.headers,
'Authorization': `Bearer ${this.accessToken}`
}
});
if (response.status === 401) {
// Token expired, try to refresh
await this.refreshToken();
return this.makeAuthenticatedRequest(url, options);
}
return response;
}
async refreshToken() {
if (this.refreshPromise) {
return this.refreshPromise;
}
this.refreshPromise = fetch('/auth/refresh', {
method: 'POST',
credentials: 'include' // Include httpOnly cookie
}).then(async response => {
if (response.ok) {
const data = await response.json();
this.setAccessToken(data.accessToken);
return data;
} else {
this.logout();
throw new Error('Token refresh failed');
}
}).finally(() => {
this.refreshPromise = null;
});
return this.refreshPromise;
}
logout() {
this.accessToken = null;
fetch('/auth/logout', {
method: 'POST',
credentials: 'include'
});
window.location.href = '/login';
}
}
HTTPS Enforcement and Transport Security
I configure applications to enforce HTTPS connections and implement HTTP Strict Transport Security headers to prevent protocol downgrade attacks.
// HTTPS enforcement middleware
const enforceHTTPS = (req, res, next) => {
if (!req.secure && req.get('x-forwarded-proto') !== 'https') {
return res.redirect(301, `https://${req.get('host')}${req.url}`);
}
next();
};
// HSTS and security headers configuration
app.use((req, res, next) => {
// HTTP Strict Transport Security
res.setHeader('Strict-Transport-Security',
'max-age=31536000; includeSubDomains; preload');
// Prevent clickjacking
res.setHeader('X-Frame-Options', 'DENY');
// Prevent MIME type sniffing
res.setHeader('X-Content-Type-Options', 'nosniff');
// XSS protection
res.setHeader('X-XSS-Protection', '1; mode=block');
// Referrer policy
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
next();
});
// Production HTTPS configuration
if (process.env.NODE_ENV === 'production') {
app.use(enforceHTTPS);
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('/path/to/private-key.pem'),
cert: fs.readFileSync('/path/to/certificate.pem'),
// Enable modern TLS protocols only
secureProtocol: 'TLSv1_2_method',
ciphers: [
'ECDHE-RSA-AES128-GCM-SHA256',
'ECDHE-RSA-AES256-GCM-SHA384',
'ECDHE-RSA-AES128-SHA256',
'ECDHE-RSA-AES256-SHA384'
].join(':'),
honorCipherOrder: true
};
https.createServer(options, app).listen(443);
}
Cross-Origin Resource Sharing Configuration
I configure CORS policies to control which domains can access API endpoints while preventing unauthorized cross-domain requests.
// Comprehensive CORS configuration
const cors = require('cors');
const corsOptions = {
origin: function (origin, callback) {
const allowedOrigins = [
'https://myapp.com',
'https://www.myapp.com',
'https://staging.myapp.com'
];
// Allow requests with no origin (mobile apps, Postman, etc.)
if (!origin) return callback(null, true);
if (allowedOrigins.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: [
'Origin',
'X-Requested-With',
'Content-Type',
'Accept',
'Authorization'
],
credentials: true, // Allow cookies
maxAge: 86400 // Cache preflight for 24 hours
};
app.use(cors(corsOptions));
// API-specific CORS for different endpoints
app.use('/api/public', cors({
origin: '*',
methods: ['GET'],
credentials: false
}));
app.use('/api/admin', cors({
origin: ['https://admin.myapp.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
credentials: true
}));
Dependency Vulnerability Management
I maintain secure codebases through regular dependency auditing and automated vulnerability scanning.
// Package.json security scripts
{
"scripts": {
"audit": "npm audit",
"audit-fix": "npm audit fix",
"security-check": "npm audit --audit-level moderate",
"outdated": "npm outdated",
"update-dependencies": "npm update"
},
"devDependencies": {
"audit-ci": "^6.6.1",
"snyk": "^1.1000.0"
}
}
# Automated security checking in CI/CD pipeline
#!/bin/bash
# Check for vulnerabilities
npm audit --audit-level high
if [ $? -ne 0 ]; then
echo "High severity vulnerabilities found!"
exit 1
fi
# Run Snyk security scan
npx snyk test
if [ $? -ne 0 ]; then
echo "Snyk found security issues!"
exit 1
fi
# Check for outdated packages
npm outdated --depth=0
I implement automated dependency checking in development workflows to catch vulnerabilities early.
// Webpack security plugin configuration
const path = require('path');
module.exports = {
// ... other webpack config
plugins: [
// Check for known vulnerabilities
new (require('webpack-bundle-analyzer').BundleAnalyzerPlugin)({
analyzerMode: process.env.NODE_ENV === 'production' ? 'static' : 'server',
openAnalyzer: false
})
],
resolve: {
// Prevent dependency confusion attacks
alias: {
'@': path.resolve(__dirname, 'src/')
}
}
};
Advanced Session Management
I implement comprehensive session management that includes proper timeout handling, secure storage, and protection against session-based attacks.
// Advanced session management
const session = require('express-session');
const MongoStore = require('connect-mongo');
const sessionConfig = {
secret: process.env.SESSION_SECRET,
name: 'sessionId', // Don't use default name
resave: false,
saveUninitialized: false,
rolling: true, // Reset expiry on activity
cookie: {
secure: process.env.NODE_ENV === 'production',
httpOnly: true,
maxAge: 30 * 60 * 1000, // 30 minutes
sameSite: 'strict'
},
store: MongoStore.create({
mongoUrl: process.env.MONGODB_URI,
touchAfter: 24 * 3600 // Lazy session update
})
};
app.use(session(sessionConfig));
// Session validation middleware
const validateSession = (req, res, next) => {
if (req.session && req.session.userId) {
// Check for session hijacking
const currentFingerprint = generateFingerprint(req);
if (req.session.fingerprint !== currentFingerprint) {
req.session.destroy();
return res.status(401).json({ error: 'Session invalid' });
}
// Update last activity
req.session.lastActivity = new Date();
next();
} else {
res.status(401).json({ error: 'Authentication required' });
}
};
// Generate browser fingerprint for session validation
function generateFingerprint(req) {
const components = [
req.get('User-Agent'),
req.get('Accept-Language'),
req.ip
];
return require('crypto')
.createHash('sha256')
.update(components.join('|'))
.digest('hex');
}
These security practices create multiple layers of protection that defend against common web vulnerabilities while maintaining application performance and user experience. Regular security audits and staying updated with emerging threats remain essential for maintaining robust security postures in modern web applications.
📘 Checkout my latest ebook for free on my channel!
Be sure to like, share, comment, and subscribe to the channel!
101 Books
101 Books is an AI-driven publishing company co-founded by author Aarav Joshi. By leveraging advanced AI technology, we keep our publishing costs incredibly low—some books are priced as low as $4—making quality knowledge accessible to everyone.
Check out our book Golang Clean Code available on Amazon.
Stay tuned for updates and exciting news. When shopping for books, search for Aarav Joshi to find more of our titles. Use the provided link to enjoy special discounts!
Our Creations
Be sure to check out our creations:
Investor Central | Investor Central Spanish | Investor Central German | Smart Living | Epochs & Echoes | Puzzling Mysteries | Hindutva | Elite Dev | JS Schools
We are on Medium
Tech Koala Insights | Epochs & Echoes World | Investor Central Medium | Puzzling Mysteries Medium | Science & Epochs Medium | Modern Hindutva
Top comments (0)