Front-end measures to prevent NoSQL injection
Basic Principles of NoSQL Injection
NoSQL injection is an attack targeting non-relational databases, where attackers construct malicious inputs to disrupt query logic or gain unauthorized data access. Unlike traditional SQL injection, NoSQL injection may involve JSON injection, operator abuse, or type confusion. For example, in MongoDB, attackers might exploit operators like $where
or $ne
to bypass authentication:
// Dangerous example: Directly concatenating user input
const query = {
username: req.body.username,
password: req.body.password
};
db.users.find(query);
When an attacker submits { "$ne": null }
as the password, they may bypass authentication. While the frontend cannot completely prevent such attacks, the following measures can significantly reduce risks.
Input Validation and Type Checking
Strict client-side validation is the first line of defense. Ensure inputs conform to expected formats and types:
function validateLogin(input: { username: string, password: string }) {
// Check if it's a string and not empty
if (typeof input.username !== 'string' || input.username.trim() === '') {
throw new Error('Invalid username');
}
// Password complexity validation
const passwordRegex = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/;
if (!passwordRegex.test(input.password)) {
throw new Error('Password must contain letters and numbers and be at least 8 characters');
}
// Prevent JSON object injection
if (typeof input.password === 'object') {
throw new Error('Illegal input format');
}
}
For numeric fields, explicitly convert and validate ranges:
function sanitizePageNumber(rawInput) {
const num = Number.parseInt(rawInput, 10);
if (Number.isNaN(num) || num < 1 || num > 100) {
return 1; // Default value
}
return num;
}
Data Serialization and Encoding
Escape special characters before sending data to the backend:
function escapeMongoOperators(input) {
if (typeof input !== 'string') return input;
const operatorPattern = /(\$[a-z]+|\$exists|\$type|\$not)/gi;
return input.replace(operatorPattern, (match) => {
return `\\${match}`;
});
}
// Usage example
const safeInput = escapeMongoOperators(userInput);
For GraphQL interfaces, use variables instead of string concatenation:
# Wrong approach
query {
users(filter: "${unsafeFilter}") { ... }
# Correct approach
query($filter: String!) {
users(filter: $filter) { ... }
}
Content Security Policy (CSP) Configuration
Restrict inline scripts and external resource loading via CSP to reduce XSS-related NoSQL injection risks:
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' 'unsafe-eval';
connect-src api.example.com;
object-src 'none'">
Secure Practices for Frontend ORMs
Use type-safe query builders to automatically defend against injection:
// Mongoose example
import mongoose from 'mongoose';
const UserSchema = new mongoose.Schema({
username: { type: String, required: true },
password: { type: String, select: false }
});
UserSchema.statics.safeFind = async function(filters) {
// Automatically escape special operators
const sanitized = Object.entries(filters).reduce((acc, [key, value]) => {
if (typeof value === 'object' && value !== null) {
throw new Error('Direct query objects are not allowed');
}
acc[key] = value;
return acc;
}, {});
return this.find(sanitized);
};
Real-Time Input Monitoring and Defense
Detect suspicious inputs dynamically during entry:
const suspiciousPatterns = [
/\$[a-z]+\(/i,
/["']\s*:\s*["']/,
/^\s*\{.*\}\s*$/
];
inputElement.addEventListener('input', (e) => {
const value = e.target.value;
if (suspiciousPatterns.some(pattern => pattern.test(value))) {
showWarning('Suspicious input characters detected');
e.target.classList.add('input-warning');
}
});
Error Message Handling
Avoid exposing detailed database errors on the client side:
fetch('/api/login', {
method: 'POST',
body: JSON.stringify(credentials)
})
.then(response => {
if (!response.ok) {
// Unified error message instead of raw errors
throw new Error('Authentication failed. Please check your credentials');
}
return response.json();
})
.catch(error => {
showToast(error.message);
});
Security Headers Configuration
Ensure API requests include security headers:
fetch('/api/data', {
headers: {
'Content-Type': 'application/json',
'X-Content-Type-Options': 'nosniff',
'X-XSS-Protection': '1; mode=block'
}
});
Frontend Storage Security
Avoid storing raw query data in localStorage:
// Unsafe
localStorage.setItem('queryParams', JSON.stringify(rawFilters));
// Safer approach
const safeFilters = {
page: Number(rawFilters.page) || 1,
search: String(rawFilters.search || '').substring(0, 100)
};
localStorage.setItem('queryParams', JSON.stringify(safeFilters));
Testing and Automated Detection
Incorporate security tests in CI pipelines:
// Jest test cases
describe('NoSQL Injection Defense', () => {
test('Should reject inputs containing operators', () => {
const maliciousInput = { username: 'admin', password: { $ne: '' } };
expect(() => validateLogin(maliciousInput)).toThrow();
});
test('Should escape MongoDB operators', () => {
expect(escapeMongoOperators('$where')).toBe('\\$where');
});
});
Development Environment Security Configuration
Pre-configure security rules in project templates:
// .eslintrc.json
{
"rules": {
"no-eval": "error",
"security/detect-object-injection": "warn",
"security/detect-non-literal-regexp": "error"
}
}
Framework-Specific Defense Measures
React example: Use controlled components with auto-escaping:
function SearchForm() {
const [input, setInput] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
const safeInput = input.replace(/[${}]/g, '');
fetchResults(safeInput);
};
return (
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
pattern="[^$}{]+"
title="Special characters are not allowed"
/>
</form>
);
}
Balancing Performance and Security
Use debouncing for high-frequency input fields:
import { debounce } from 'lodash';
const validateInput = debounce((value) => {
if (value.includes('$')) {
highlightSecurityWarning();
}
}, 300);
inputElement.addEventListener('input', (e) => {
validateInput(e.target.value);
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:防止 SQL 注入的前端措施