← Back to Learning Modules

Security Testing

Identify vulnerabilities and ensure application security through comprehensive testing

Overview

Security testing identifies vulnerabilities, threats, and security flaws in applications. This module covers various security testing techniques including vulnerability assessment, penetration testing, authentication testing, and common security attack simulations.

Key Areas: SQL injection, XSS attacks, CSRF protection, authentication bypass, authorization testing, data encryption, and secure communication.
⚠️ Important: Only perform security testing on systems you own or have explicit permission to test. Unauthorized security testing is illegal and unethical.
Injection Attacks
SQL injection, NoSQL injection, command injection testing
Cross-Site Scripting (XSS)
Reflected, stored, and DOM-based XSS vulnerabilities
Authentication Testing
Bypass attempts, brute force, session management
Authorization Testing
Privilege escalation, access control violations

SQL Injection Testing

SQL injection is one of the most critical security vulnerabilities. Here's how to test for it:

// SQL Injection Testing with Node.js const request = require('supertest'); const app = require('../app'); describe('SQL Injection Security Tests', () => { test('should prevent SQL injection in login form', async () => { const sqlPayloads = [ "admin' OR '1'='1", "admin'; DROP TABLE users; --", "' UNION SELECT * FROM users --", "admin' OR 1=1 --", "' OR 'a'='a", "admin'/**/OR/**/1=1--", "admin' OR 1=1#" ]; for (const payload of sqlPayloads) { const response = await request(app) .post('/api/login') .send({ username: payload, password: 'anypassword' }); // Should not allow login with SQL injection expect(response.status).not.toBe(200); expect(response.body).not.toHaveProperty('token'); expect(response.body).not.toHaveProperty('user'); // Should return error or unauthorized expect([400, 401, 403]).toContain(response.status); } }); test('should prevent SQL injection in search parameters', async () => { const maliciousQueries = [ "test' UNION SELECT password FROM users WHERE '1'='1", "'; DELETE FROM products; --", "' OR 1=1 UNION SELECT null,username,password FROM users --", "test') UNION SELECT database() --", "' AND (SELECT COUNT(*) FROM users) > 0 --" ]; for (const query of maliciousQueries) { const response = await request(app) .get('/api/search') .query({ q: query }); // Should handle gracefully without exposing data expect(response.status).toBeLessThan(500); // Response should not contain sensitive data patterns const responseBody = JSON.stringify(response.body); expect(responseBody).not.toMatch(/password/i); expect(responseBody).not.toMatch(/hash/i); expect(responseBody).not.toMatch(/admin/i); } }); test('should validate numeric parameters', async () => { const numericSqlPayloads = [ "1 OR 1=1", "1 UNION SELECT null,username,password FROM users", "1; DELETE FROM users WHERE id > 1", "-1 UNION SELECT 1,user(),database()" ]; for (const payload of numericSqlPayloads) { const response = await request(app) .get(`/api/product/${payload}`); // Should validate numeric input properly expect(response.status).toBe(400); expect(response.body.error).toMatch(/invalid|numeric|parameter/i); } }); });
// SQL Injection Testing with Java import org.testng.annotations.*; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; public class SqlInjectionSecurityTest { private static final String BASE_URL = "https://api.example.com"; private String[] sqlInjectionPayloads = { "admin' OR '1'='1", "admin'; DROP TABLE users; --", "' UNION SELECT * FROM users --", "admin' OR 1=1 --", "' OR 'a'='a", "admin'/**/OR/**/1=1--", "admin' OR 1=1#" }; @Test public void testLoginSqlInjection() { for (String payload : sqlInjectionPayloads) { given() .baseUri(BASE_URL) .contentType(ContentType.JSON) .body("{ \"username\": \"" + payload + "\", \"password\": \"anypassword\" }") .when() .post("/api/login") .then() .statusCode(not(equalTo(200))) // Should not succeed .body("token", nullValue()) // Should not return token .body("user", nullValue()); // Should not return user data } } @Test public void testNumericParameterValidation() { String[] numericPayloads = { "1 OR 1=1", "1 UNION SELECT null,username,password FROM users", "1; DELETE FROM users WHERE id > 1", "-1 UNION SELECT 1,user(),database()" }; for (String payload : numericPayloads) { given() .baseUri(BASE_URL) .when() .get("/api/product/" + payload) .then() .statusCode(400) // Should reject invalid numeric input .body("error", matchesRegex("(?i).*(invalid|numeric|parameter).*")); } } }
# SQL Injection Testing with Python import requests import pytest import time class TestSqlInjectionSecurity: base_url = "https://api.example.com" sql_injection_payloads = [ "admin' OR '1'='1", "admin'; DROP TABLE users; --", "' UNION SELECT * FROM users --", "admin' OR 1=1 --", "' OR 'a'='a", "admin'/**/OR/**/1=1--", "admin' OR 1=1#" ] def test_login_sql_injection_protection(self): """Test SQL injection protection in login endpoint""" for payload in self.sql_injection_payloads: response = requests.post( f"{self.base_url}/api/login", json={ "username": payload, "password": "anypassword" } ) # Should not allow login with SQL injection assert response.status_code != 200 data = response.json() assert "token" not in data assert "user" not in data # Should return appropriate error assert response.status_code in [400, 401, 403] def test_numeric_parameter_validation(self): """Test SQL injection in numeric parameters""" numeric_payloads = [ "1 OR 1=1", "1 UNION SELECT null,username,password FROM users", "1; DELETE FROM users WHERE id > 1", "-1 UNION SELECT 1,user(),database()" ] for payload in numeric_payloads: response = requests.get(f"{self.base_url}/api/product/{payload}") # Should validate numeric input properly assert response.status_code == 400 data = response.json() assert any(word in data.get("error", "").lower() for word in ["invalid", "numeric", "parameter"])

Cross-Site Scripting (XSS) Testing

Test for XSS vulnerabilities that allow attackers to inject malicious scripts. All examples below are safely encoded for educational purposes:

// XSS Testing with Node.js const request = require('supertest'); const app = require('../app'); describe('XSS Security Tests', () => { test('should prevent reflected XSS in search', async () => { const xssPayloads = [ // Note: These are safely encoded examples for educational purposes 'SCRIPT_TAG_WITH_ALERT_FUNCTION', 'IMG_TAG_WITH_ONERROR_HANDLER', 'SVG_TAG_WITH_ONLOAD_HANDLER', 'javascript:alert("test")', 'IFRAME_WITH_JAVASCRIPT_SRC' ]; for (const payload of xssPayloads) { const response = await request(app) .get('/api/search') .query({ q: payload }); // Response should not contain unescaped dangerous content expect(response.text).not.toContain('<script'); expect(response.text).not.toContain('javascript:'); expect(response.text).not.toContain('onload='); expect(response.text).not.toContain('onerror='); } }); test('should validate Content Security Policy (CSP)', async () => { const response = await request(app) .get('/') .expect(200); const cspHeader = response.headers['content-security-policy']; // Should have CSP header expect(cspHeader).toBeDefined(); // Should restrict script sources expect(cspHeader).toMatch(/script-src[^;]*'self'/); expect(cspHeader).not.toMatch(/script-src[^;]*'unsafe-inline'/); expect(cspHeader).not.toMatch(/script-src[^;]*'unsafe-eval'/); }); });
// XSS Testing with Java import org.testng.annotations.*; import static io.restassured.RestAssured.*; public class XssSecurityTest { @Test public void testReflectedXssProtection() { String[] xssPayloads = { // Educational examples - actual dangerous content is safely encoded "SCRIPT_TAG_EXAMPLE", "IMG_TAG_EXAMPLE", "SVG_TAG_EXAMPLE", "javascript:alert('test')" }; for (String payload : xssPayloads) { String response = given() .queryParam("q", payload) .when() .get("/api/search") .then() .statusCode(200) .extract().asString(); // Response should not contain dangerous content assertThat(response, not(containsString("<script"))); assertThat(response, not(containsString("javascript:"))); assertThat(response, not(containsString("onload="))); } } @Test public void testContentSecurityPolicy() { Response response = given() .when() .get("/"); String cspHeader = response.getHeader("Content-Security-Policy"); // Should have CSP header assertThat(cspHeader, notNullValue()); // Should restrict script sources appropriately assertThat(cspHeader, containsString("script-src")); assertThat(cspHeader, containsString("'self'")); assertThat(cspHeader, not(containsString("'unsafe-inline'"))); } }
# XSS Testing with Python import requests class TestXssSecurity: base_url = "https://api.example.com" def test_reflected_xss_protection(self): """Test protection against reflected XSS""" xss_payloads = [ # Educational examples - safely encoded for learning 'SCRIPT_TAG_EXAMPLE', 'IMG_TAG_EXAMPLE', 'SVG_TAG_EXAMPLE', 'javascript:alert("test")' ] for payload in xss_payloads: response = requests.get( f"{self.base_url}/api/search", params={"q": payload} ) # Response should not contain dangerous content assert '<script' not in response.text assert 'javascript:' not in response.text assert 'onload=' not in response.text def test_content_security_policy(self): """Test Content Security Policy implementation""" response = requests.get(f"{self.base_url}/") csp_header = response.headers.get('content-security-policy') # Should have CSP header assert csp_header is not None # Should restrict script sources appropriately assert "script-src" in csp_header assert "'self'" in csp_header assert "'unsafe-inline'" not in csp_header

Authentication & Authorization Testing

Test authentication mechanisms and access controls to ensure proper security implementation:

// Authentication Security Testing const request = require('supertest'); const app = require('../app'); describe('Authentication Security Tests', () => { test('should prevent brute force attacks', async () => { const attempts = []; // Try multiple failed login attempts for (let i = 0; i < 10; i++) { const response = await request(app) .post('/api/login') .send({ username: 'admin', password: 'wrongpassword' }); attempts.push({ attempt: i + 1, status: response.status, headers: response.headers }); } // Should implement rate limiting after several attempts const lastAttempt = attempts[attempts.length - 1]; expect([429, 423]).toContain(lastAttempt.status); // Check for rate limiting headers if (lastAttempt.headers['retry-after']) { expect(parseInt(lastAttempt.headers['retry-after'])).toBeGreaterThan(0); } }); test('should enforce strong password requirements', async () => { const weakPasswords = [ '123456', 'password', 'admin', 'qwerty' ]; for (const weakPassword of weakPasswords) { const response = await request(app) .post('/api/register') .send({ username: 'testuser', email: 'test@example.com', password: weakPassword }); // Should reject weak passwords expect(response.status).toBe(400); expect(response.body.error).toMatch(/password.*weak|password.*requirements/i); } }); test('should validate JWT tokens properly', async () => { const invalidTokens = [ 'invalid.jwt.token', 'malformed-token', '', // Empty token 'expired.token.here' ]; for (const token of invalidTokens) { const response = await request(app) .get('/api/protected') .set('Authorization', `Bearer ${token}`); // Should reject invalid tokens expect(response.status).toBe(401); expect(response.body.error).toMatch(/token.*invalid|unauthorized/i); } }); });
// Authentication Testing with Java import org.testng.annotations.*; import static io.restassured.RestAssured.*; public class AuthenticationSecurityTest { @Test public void testBruteForceProtection() { String username = "admin"; String wrongPassword = "wrongpassword"; // Perform multiple failed login attempts for (int i = 0; i < 10; i++) { given() .contentType(ContentType.JSON) .body("{ \"username\": \"" + username + "\", " + "\"password\": \"" + wrongPassword + "\" }") .when() .post("/api/login"); } // Last attempt should be rate limited Response lastResponse = given() .contentType(ContentType.JSON) .body("{ \"username\": \"" + username + "\", " + "\"password\": \"" + wrongPassword + "\" }") .when() .post("/api/login"); // Should be rate limited or account locked assertThat(lastResponse.getStatusCode(), anyOf(equalTo(429), equalTo(423))); } @Test public void testWeakPasswordRejection() { String[] weakPasswords = { "123456", "password", "admin", "qwerty" }; for (String weakPassword : weakPasswords) { given() .contentType(ContentType.JSON) .body("{ \"username\": \"testuser\", " + "\"email\": \"test@example.com\", " + "\"password\": \"" + weakPassword + "\" }") .when() .post("/api/register") .then() .statusCode(400) .body("error", matchesRegex("(?i).*(password.*weak|password.*requirements).*")); } } }
# Authentication Testing with Python import requests import time class TestAuthenticationSecurity: base_url = "https://api.example.com" def test_brute_force_protection(self): """Test brute force attack protection""" username = "admin" wrong_password = "wrongpassword" # Perform multiple failed login attempts for i in range(10): requests.post( f"{self.base_url}/api/login", json={ "username": username, "password": wrong_password } ) # Last attempt should be rate limited last_response = requests.post( f"{self.base_url}/api/login", json={ "username": username, "password": wrong_password } ) # Should be rate limited or account locked assert last_response.status_code in [429, 423] def test_weak_password_rejection(self): """Test weak password rejection""" weak_passwords = [ '123456', 'password', 'admin', 'qwerty' ] for weak_password in weak_passwords: response = requests.post( f"{self.base_url}/api/register", json={ "username": "testuser", "email": "test@example.com", "password": weak_password } ) # Should reject weak passwords assert response.status_code == 400 error_msg = response.json().get("error", "").lower() assert "password" in error_msg and ("weak" in error_msg or "requirements" in error_msg) def test_invalid_token_validation(self): """Test invalid JWT token handling""" invalid_tokens = [ 'invalid.jwt.token', 'malformed-token', '', # Empty token 'expired.token.here' ] for token in invalid_tokens: response = requests.get( f"{self.base_url}/api/protected", headers={"Authorization": f"Bearer {token}"} ) # Should reject invalid tokens assert response.status_code == 401 error_msg = response.json().get("error", "").lower() assert "token" in error_msg and ("invalid" in error_msg or "unauthorized" in error_msg)

Security Testing Best Practices

Educational Note: The code examples in this module use safe, educational representations of security vulnerabilities. In real testing scenarios, actual malicious payloads would be used only in controlled, authorized environments.