Injection Attacks in JavaScript
Injection Attacks in JavaScript
While SQL injection is well-known, JavaScript applications face various injection attacks including NoSQL injection, command injection in Node.js, and template injection. These vulnerabilities occur when user input is improperly incorporated into database queries, system commands, or template engines.
// NoSQL Injection Prevention
// VULNERABLE: MongoDB query with user input
async function vulnerableLogin(username, password) {
// This allows injection like: username = {$ne: null}
const user = await db.collection('users').findOne({
username: username,
password: password
});
return user;
}
// SECURE: Validate and sanitize inputs
async function secureLogin(username, password) {
// Type validation
if (typeof username !== 'string' || typeof password !== 'string') {
throw new Error('Invalid input types');
}
// Length and character validation
if (username.length > 50 || !/^[a-zA-Z0-9_-]+$/.test(username)) {
throw new Error('Invalid username format');
}
// Use parameterized queries where possible
const user = await db.collection('users').findOne({
username: { $eq: username }, // Explicit equality
password: { $eq: hashPassword(password) }
});
return user;
}
// Command Injection Prevention in Node.js
const { spawn } = require('child_process');
const path = require('path');
// VULNERABLE: Command injection
function vulnerableImageResize(userFilename, size) {
// This allows injection like: userFilename = "image.jpg; rm -rf /"
const command = `convert ${userFilename} -resize ${size} output.jpg`;
require('child_process').exec(command); // DANGEROUS!
}
// SECURE: Use spawn with argument array
function secureImageResize(userFilename, size) {
// Validate inputs
if (!/^[a-zA-Z0-9_-]+\.(jpg|png|gif)$/i.test(userFilename)) {
throw new Error('Invalid filename');
}
if (!/^\d+x\d+$/.test(size)) {
throw new Error('Invalid size format');
}
// Ensure file exists and is in allowed directory
const safePath = path.join(__dirname, 'uploads', userFilename);
if (!safePath.startsWith(path.join(__dirname, 'uploads'))) {
throw new Error('Path traversal attempt');
}
// Use spawn with separate arguments (no shell)
const convert = spawn('convert', [
safePath,
'-resize', size,
path.join(__dirname, 'output', 'resized-' + userFilename)
], {
timeout: 30000, // 30 second timeout
cwd: __dirname,
env: {} // Minimal environment
});
return new Promise((resolve, reject) => {
convert.on('exit', (code) => {
if (code === 0) resolve();
else reject(new Error(`Process exited with code ${code}`));
});
});
}
// Template Injection Prevention
// VULNERABLE: User input in template string
function vulnerableTemplate(userInput) {
// This allows code execution!
return eval(`\`Hello ${userInput}\``);
}
// SECURE: Safe template rendering
function secureTemplate(data) {
// Use a proper template engine with auto-escaping
const Handlebars = require('handlebars');
// Compile template
const template = Handlebars.compile('Hello {{name}}');
// Data is automatically escaped
return template({ name: data.userInput });
}
// For dynamic templates, use sandboxing
const vm = require('vm');
function sandboxedTemplate(templateStr, context) {
// Create a limited context
const sandbox = {
data: context,
console: { log: () => {} }, // Limited console
// Don't expose dangerous globals
};
// Run in sandbox with timeout
try {
const script = new vm.Script(`
// Limit template processing
const result = data.name ? \`Hello \${data.name}\` : 'Hello Guest';
result;
`);
return script.runInNewContext(sandbox, {
timeout: 100, // 100ms timeout
displayErrors: false
});
} catch (error) {
throw new Error('Template processing failed');
}
}
Understanding JavaScript vulnerabilities is crucial for building secure applications. The dynamic nature of JavaScript, combined with its execution in untrusted environments, creates unique security challenges. By recognizing these vulnerabilities and implementing proper defenses, developers can significantly improve their applications' security posture.## Secure Coding Standards
Establishing and following secure coding standards is fundamental to building resilient applications that can withstand modern security threats. These standards provide developers with clear guidelines on how to write code that is not only functional but also secure by design. This chapter presents comprehensive secure coding standards for both Python and JavaScript, covering everything from naming conventions and code organization to specific security patterns and anti-patterns that every developer should know.