UNPKG

saksh-secure

Version:

A Node.js tool to investigate login form security and performance issues

209 lines (192 loc) 7.41 kB
const axios = require('axios').create({ jar: require('tough-cookie').CookieJar() }); const { performance } = require('perf_hooks'); const tough = require('tough-cookie'); async function testBasicLogin(config) { const startTime = performance.now(); try { const response = await axios.post(config.targetUrl, { [config.usernameField]: config.commonUsernames[0], [config.passwordField]: config.commonPasswords[0] }, { timeout: config.timeout }); return { status: response.status, success: response.data.success || false, message: response.data.message || 'No message', responseTime: `${(performance.now() - startTime).toFixed(2)}ms` }; } catch (error) { return { status: error.response?.status || 'N/A', error: error.message, responseTime: `${(performance.now() - startTime).toFixed(2)}ms` }; } } async function testSqlInjection(config) { const results = []; for (const payload of config.sqlInjectionPayloads) { const result = await testBasicLogin({ ...config, commonUsernames: [payload], commonPasswords: [payload] }); results.push({ payload, ...result, potentialVulnerability: result.success || result.message.includes('success') }); } return results; } async function testXssVulnerability(config) { const results = []; for (const payload of config.xssPayloads) { const result = await testBasicLogin({ ...config, commonUsernames: [payload], commonPasswords: [payload] }); const isReflected = result.message?.includes(payload) || result.error?.includes(payload); results.push({ payload, ...result, potentialXss: isReflected || result.status === 200 }); } return results; } async function testSessionManagement(config) { try { const response = await axios.post(config.targetUrl, { [config.usernameField]: config.commonUsernames[0], [config.passwordField]: config.commonPasswords[0] }, { timeout: config.timeout }); const cookies = response.headers['set-cookie'] || []; const cookieDetails = cookies.map(cookie => { const parsed = tough.parse(cookie); return { name: parsed?.key, secure: parsed?.secure || false, httpOnly: parsed?.httpOnly || false, sameSite: parsed?.sameSite || 'None' }; }); return { status: response.status, cookiesSet: cookieDetails, secureCookies: cookieDetails.every(c => c.secure && c.httpOnly), message: response.data.message || 'No message' }; } catch (error) { return { status: error.response?.status || 'N/A', error: error.message, cookiesSet: [] }; } } async function testCsrfProtection(config) { try { const response = await axios.post(config.targetUrl, { [config.usernameField]: config.commonUsernames[0], [config.passwordField]: config.commonPasswords[0] }, { timeout: config.timeout, maxRedirects: 0 }); return { status: response.status, message: response.data.message || 'No message', csrfProtection: response.status === 403 || response.data.message.includes('CSRF') }; } catch (error) { return { status: error.response?.status || 'N/A', error: error.message, csrfProtection: error.response?.status === 403 || error.message.includes('CSRF') }; } } async function testPasswordPolicy(config) { const results = []; for (const password of config.weakPasswords) { const result = await testBasicLogin({ ...config, commonPasswords: [password] }); results.push({ password, ...result, policyEnforced: result.message.includes('password') && result.status !== 200 }); } return results; } async function testRateLimiting(config) { const results = []; for (let i = 0; i < config.maxAttempts + 2; i++) { const result = await testBasicLogin(config); results.push({ attempt: i + 1, ...result, rateLimitDetected: result.status === 429 || result.message.includes('too many requests'), captchaDetected: result.message.includes('CAPTCHA') || result.message.includes('verify') }); await new Promise(resolve => setTimeout(resolve, 500)); } return results; } async function testHttpsEnforcement(config) { const httpUrl = config.targetUrl.replace('https://', 'http://'); try { const response = await axios.post(httpUrl, { [config.usernameField]: config.commonUsernames[0], [config.passwordField]: config.commonPasswords[0] }, { timeout: config.timeout, maxRedirects: 0 }); return { status: response.status, message: 'HTTP request succeeded', httpsEnforced: false }; } catch (error) { return { status: error.response?.status || 'N/A', error: error.message, httpsEnforced: error.message.includes('redirect') || error.response?.status === 301 || error.response?.status === 302 }; } } async function testAccountLockout(config) { const results = []; for (let i = 0; i < 10; i++) { const result = await testBasicLogin({ ...config, commonPasswords: ['wrongpassword'] }); results.push({ attempt: i + 1, ...result, lockoutDetected: result.message.includes('locked') || result.status === 403 }); await new Promise(resolve => setTimeout(resolve, 1000)); } return results; } async function testPerformance(config) { const results = []; const testCases = [ { username: config.commonUsernames[0], password: config.commonPasswords[0] }, { username: 'invalid', password: 'invalid' }, { username: 'x'.repeat(1000), password: 'x'.repeat(1000) } ]; for (const testCase of testCases) { const times = []; for (let i = 0; i < 5; i++) { const startTime = performance.now(); await testBasicLogin({ ...config, commonUsernames: [testCase.username], commonPasswords: [testCase.password] }); times.push(performance.now() - startTime); await new Promise(resolve => setTimeout(resolve, 500)); } results.push({ testCase, averageResponseTime: (times.reduce((a, b) => a + b, 0) / times.length).toFixed(2) + 'ms', maxResponseTime: Math.max(...times).toFixed(2) + 'ms' }); } return results; } module.exports = { testBasicLogin, testSqlInjection, testXssVulnerability, testSessionManagement, testCsrfProtection, testPasswordPolicy, testRateLimiting, testHttpsEnforcement, testAccountLockout, testPerformance };