medienkompetenz-lernplattform/backend/lessons/modules/sql-injection-shop/index.js
2026-02-05 22:42:30 +01:00

210 lines
7.6 KiB
JavaScript

const LessonModule = require('../base/LessonModule');
class SQLInjectionShopLesson extends LessonModule {
constructor(config) {
super(config);
}
// Mock database with products
getMockDatabase() {
return {
products: [
{ id: 1, name: 'Laptop Pro 15', price: 1299.99, category: 'Electronics', stock: 15 },
{ id: 2, name: 'Wireless Mouse', price: 29.99, category: 'Accessories', stock: 50 },
{ id: 3, name: 'USB-C Cable', price: 12.99, category: 'Accessories', stock: 100 },
{ id: 4, name: 'Gaming Keyboard', price: 89.99, category: 'Electronics', stock: 25 },
{ id: 5, name: 'Monitor 27"', price: 349.99, category: 'Electronics', stock: 20 },
{ id: 6, name: 'Webcam HD', price: 79.99, category: 'Electronics', stock: 30 },
{ id: 7, name: 'Desk Lamp', price: 34.99, category: 'Office', stock: 40 },
{ id: 8, name: 'Notebook Set', price: 15.99, category: 'Office', stock: 60 }
],
users: [
{ id: 1, username: 'admin', password: 'hashed_admin_password', role: 'admin' },
{ id: 2, username: 'john_doe', password: 'hashed_user_password', role: 'customer' },
{ id: 3, username: 'jane_smith', password: 'hashed_user_password', role: 'customer' }
],
orders: [
{ id: 1, user_id: 2, total: 1329.98, status: 'shipped' },
{ id: 2, user_id: 3, total: 89.99, status: 'processing' }
]
};
}
// Simulate vulnerable SQL query
executeVulnerableQuery(searchTerm) {
const db = this.getMockDatabase();
// Build the "vulnerable" query string for educational display
const vulnerableQuery = `SELECT * FROM products WHERE name LIKE '%${searchTerm}%'`;
// Detect SQL injection attempts
const injectionDetected = this.detectInjection(searchTerm);
let results = [];
let injectionType = null;
let explanation = '';
if (injectionDetected) {
const injectionInfo = this.analyzeInjection(searchTerm);
injectionType = injectionInfo.type;
explanation = injectionInfo.explanation;
// Simulate different injection results
if (injectionInfo.type === 'OR_ALWAYS_TRUE') {
// Return all products (simulating OR '1'='1')
results = db.products;
} else if (injectionInfo.type === 'UNION_SELECT') {
// Simulate UNION attack showing user data
results = [
{ id: 'INJECTED', name: 'admin', price: 'hashed_admin_password', category: 'LEAKED DATA', stock: 'admin' },
{ id: 'INJECTED', name: 'john_doe', price: 'hashed_user_password', category: 'LEAKED DATA', stock: 'customer' },
{ id: 'INJECTED', name: 'jane_smith', price: 'hashed_user_password', category: 'LEAKED DATA', stock: 'customer' }
];
} else if (injectionInfo.type === 'DROP_TABLE') {
// Simulate destructive command
results = [];
explanation += ' In a real scenario, this could delete the entire products table!';
} else if (injectionInfo.type === 'COMMENT_INJECTION') {
// Bypass rest of query
results = db.products;
}
} else {
// Normal search - filter products by name
results = db.products.filter(p =>
p.name.toLowerCase().includes(searchTerm.toLowerCase())
);
}
return {
query: vulnerableQuery,
results,
injectionDetected,
injectionType,
explanation,
recordCount: results.length
};
}
// Detect if input contains SQL injection
detectInjection(input) {
const injectionPatterns = [
/'/, // Single quote
/--/, // SQL comment
/;/, // Statement separator
/union/i, // UNION keyword
/select/i, // SELECT keyword
/drop/i, // DROP keyword
/insert/i, // INSERT keyword
/update/i, // UPDATE keyword
/delete/i, // DELETE keyword
/or\s+['"]?\d+['"]?\s*=\s*['"]?\d+['"]?/i // OR 1=1 pattern
];
return injectionPatterns.some(pattern => pattern.test(input));
}
// Analyze the type of SQL injection
analyzeInjection(input) {
const lowerInput = input.toLowerCase();
if (lowerInput.includes('union') && lowerInput.includes('select')) {
return {
type: 'UNION_SELECT',
explanation: '⚠️ UNION SELECT injection detected! This technique combines results from multiple tables, potentially exposing sensitive data like usernames and passwords.'
};
}
if (lowerInput.includes('drop')) {
return {
type: 'DROP_TABLE',
explanation: '🚨 DROP TABLE injection detected! This is a destructive attack that could delete entire database tables. Critical data loss would occur!'
};
}
if (lowerInput.includes("'") && (lowerInput.includes('or') || lowerInput.includes('||'))) {
if (lowerInput.match(/or\s+['"]?\d+['"]?\s*=\s*['"]?\d+['"]?/)) {
return {
type: 'OR_ALWAYS_TRUE',
explanation: "⚠️ OR injection detected! The condition '1'='1' is always true, bypassing the intended filter and returning ALL records."
};
}
}
if (lowerInput.includes('--') || lowerInput.includes('#')) {
return {
type: 'COMMENT_INJECTION',
explanation: '⚠️ Comment injection detected! The -- sequence comments out the rest of the SQL query, potentially bypassing security checks.'
};
}
if (lowerInput.includes(';')) {
return {
type: 'MULTIPLE_STATEMENTS',
explanation: '⚠️ Multiple statement injection detected! The semicolon allows execution of additional SQL commands, enabling complex attacks.'
};
}
// Generic injection
return {
type: 'GENERIC',
explanation: '⚠️ SQL injection attempt detected! Special characters in the input could manipulate the query structure.'
};
}
// Demonstrate safe parameterized query
executeSafeQuery(searchTerm) {
const db = this.getMockDatabase();
// Show the safe query with placeholder
const safeQuery = `SELECT * FROM products WHERE name LIKE ?`;
const parameter = `%${searchTerm}%`;
// Execute safe search (treats all input as literal data)
const results = db.products.filter(p =>
p.name.toLowerCase().includes(searchTerm.toLowerCase())
);
return {
query: safeQuery,
parameter,
results,
explanation: '✅ Parameterized query used! User input is treated as data only, never as SQL code. Injection is impossible.',
recordCount: results.length
};
}
// Get interactive data for the SQL shop demo
getInteractiveData(stepId) {
if (stepId === 'shop-demo') {
return {
database: this.getMockDatabase(),
examples: [
{
label: 'Normal Search',
input: 'laptop',
description: 'Search for products containing "laptop"'
},
{
label: 'View All Products (OR injection)',
input: "' OR '1'='1",
description: 'Exploit: Returns all products by making condition always true'
},
{
label: 'Extract User Data (UNION)',
input: "' UNION SELECT id, username, password, role, 'LEAKED' FROM users--",
description: 'Exploit: Combines product results with user table data'
},
{
label: 'Destructive Attack (DROP)',
input: "'; DROP TABLE products--",
description: 'Exploit: Attempts to delete the products table'
}
]
};
}
return null;
}
}
module.exports = SQLInjectionShopLesson;