Prerequisites
- Basic understanding of JavaScript ๐
- TypeScript installation โก
- VS Code or preferred IDE ๐ป
What you'll learn
- Understand security testing fundamentals ๐ฏ
- Apply OWASP principles in real projects ๐๏ธ
- Debug common security issues ๐
- Write type-safe secure code โจ
๐ฏ Introduction
Welcome to the crucial world of security testing with TypeScript! ๐ก๏ธ In this guide, weโll explore how to build applications that stand strong against security threats using OWASP (Open Web Application Security Project) principles.
Youโll discover how proper security testing can protect your TypeScript applications from the most common vulnerabilities. Whether youโre building web applications ๐, APIs ๐ฅ๏ธ, or full-stack systems ๐, understanding OWASP compliance is essential for creating secure, trustworthy software.
By the end of this tutorial, youโll feel confident implementing robust security testing in your own projects! Letโs fortify your code! ๐ฐ
๐ Understanding OWASP Security Testing
๐ค What is OWASP?
OWASP is like a security guard ๐ก๏ธ for your web applications. Think of it as a comprehensive guidebook ๐ that helps you identify and prevent the most dangerous security vulnerabilities that hackers love to exploit.
In TypeScript terms, OWASP provides a framework for identifying security risks and implementing protective measures โจ. This means you can:
- โจ Prevent injection attacks
- ๐ Secure authentication and session management
- ๐ก๏ธ Protect sensitive data exposure
- ๐ Implement proper access controls
๐ก Why Use OWASP Security Testing?
Hereโs why developers prioritize OWASP compliance:
- Proven Framework ๐: Battle-tested against real-world threats
- Industry Standard ๐ป: Recognized globally by security professionals
- Comprehensive Coverage ๐: Addresses top security vulnerabilities
- Community Support ๐ง: Constantly updated by security experts
Real-world example: Imagine building an e-commerce platform ๐. With OWASP compliance, you can protect customer payment data, prevent SQL injection, and secure user accounts against breaches.
๐ง Basic Security Testing Setup
๐ Essential Security Test Types
Letโs start with fundamental security testing patterns:
// ๐ก๏ธ Security testing utilities
interface SecurityTestConfig {
enableSqlInjectionTests: boolean; // ๐ SQL injection protection
enableXssTests: boolean; // ๐ซ Cross-site scripting protection
enableCsrfTests: boolean; // ๐ก๏ธ CSRF token validation
enableAuthTests: boolean; // ๐ Authentication security
}
// ๐ฏ Security test framework
class SecurityTester {
private config: SecurityTestConfig;
constructor(config: SecurityTestConfig) {
this.config = config;
console.log("๐ Security testing framework initialized!");
}
// ๐งช Run all security tests
async runSecuritySuite(): Promise<SecurityTestResult[]> {
const results: SecurityTestResult[] = [];
if (this.config.enableSqlInjectionTests) {
results.push(await this.testSqlInjection());
}
if (this.config.enableXssTests) {
results.push(await this.testXssVulnerabilities());
}
return results;
}
}
๐ก Explanation: Notice how we structure security tests systematically! Each test type can be enabled/disabled for targeted testing scenarios.
๐ฏ Input Validation Testing
Here are patterns youโll use to prevent injection attacks:
// โ ๏ธ Input validation for security
interface ValidationResult {
isValid: boolean;
errors: string[];
sanitizedInput?: string;
}
// ๐ก๏ธ Secure input validator
class SecureInputValidator {
// ๐ Prevent SQL injection
validateSqlInput(input: string): ValidationResult {
const sqlInjectionPattern = /(\b(SELECT|INSERT|UPDATE|DELETE|DROP|UNION|ALTER)\b)/i;
if (sqlInjectionPattern.test(input)) {
return {
isValid: false,
errors: ["๐จ Potential SQL injection detected!"]
};
}
return {
isValid: true,
errors: [],
sanitizedInput: this.sanitizeInput(input)
};
}
// ๐ซ Prevent XSS attacks
validateXssInput(input: string): ValidationResult {
const xssPattern = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi;
if (xssPattern.test(input)) {
return {
isValid: false,
errors: ["๐จ Potential XSS attempt detected!"]
};
}
return {
isValid: true,
errors: [],
sanitizedInput: this.escapeHtml(input)
};
}
// ๐งน Sanitize dangerous input
private sanitizeInput(input: string): string {
return input.replace(/['"`;\\]/g, ''); // ๐งฝ Remove dangerous characters
}
// ๐ก๏ธ Escape HTML entities
private escapeHtml(input: string): string {
return input
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
}
๐ก Practical Security Testing Examples
๐ Example 1: E-Commerce Security Testing
Letโs build a secure shopping system:
// ๐๏ธ Secure user interface
interface SecureUser {
id: string;
email: string;
hashedPassword: string; // ๐ Never store plain passwords!
role: 'customer' | 'admin';
sessionToken?: string;
}
// ๐ณ Secure payment data
interface SecurePayment {
transactionId: string;
amount: number;
currency: string;
encryptedCardData: string; // ๐ก๏ธ Always encrypt sensitive data
timestamp: Date;
}
// ๐ Secure e-commerce class with built-in testing
class SecureECommerceSystem {
private users: Map<string, SecureUser> = new Map();
private validator = new SecureInputValidator();
// ๐ Secure user registration
async registerUser(email: string, password: string): Promise<{success: boolean, errors: string[]}> {
// ๐ง Validate email format
const emailValidation = this.validateEmail(email);
if (!emailValidation.isValid) {
return { success: false, errors: emailValidation.errors };
}
// ๐ Validate password strength
const passwordValidation = this.validatePasswordStrength(password);
if (!passwordValidation.isValid) {
return { success: false, errors: passwordValidation.errors };
}
// ๐ง Hash password with salt
const hashedPassword = await this.hashPassword(password);
const user: SecureUser = {
id: this.generateSecureId(),
email: email.toLowerCase().trim(),
hashedPassword,
role: 'customer'
};
this.users.set(user.id, user);
console.log(`โ
User registered securely: ${user.email}`);
return { success: true, errors: [] };
}
// ๐ณ Secure payment processing
async processPayment(userId: string, paymentData: Omit<SecurePayment, 'transactionId' | 'encryptedCardData' | 'timestamp'>): Promise<{success: boolean, transactionId?: string}> {
// ๐ Validate user exists and is authenticated
const user = this.users.get(userId);
if (!user || !user.sessionToken) {
console.log("๐จ Unauthorized payment attempt!");
return { success: false };
}
// ๐ฐ Validate payment amount
if (paymentData.amount <= 0 || paymentData.amount > 10000) {
console.log("โ ๏ธ Invalid payment amount detected!");
return { success: false };
}
// ๐ Create secure transaction
const transaction: SecurePayment = {
transactionId: this.generateSecureId(),
...paymentData,
encryptedCardData: "ENCRYPTED_DATA_PLACEHOLDER", // ๐ก๏ธ Would use real encryption
timestamp: new Date()
};
console.log(`๐ธ Payment processed securely: $${paymentData.amount}`);
return { success: true, transactionId: transaction.transactionId };
}
// ๐ Password strength validation
private validatePasswordStrength(password: string): ValidationResult {
const errors: string[] = [];
if (password.length < 8) {
errors.push("๐จ Password must be at least 8 characters");
}
if (!/[A-Z]/.test(password)) {
errors.push("๐จ Password must contain uppercase letters");
}
if (!/[0-9]/.test(password)) {
errors.push("๐จ Password must contain numbers");
}
if (!/[!@#$%^&*]/.test(password)) {
errors.push("๐จ Password must contain special characters");
}
return {
isValid: errors.length === 0,
errors
};
}
// ๐ง Email validation
private validateEmail(email: string): ValidationResult {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
return {
isValid: false,
errors: ["๐จ Invalid email format"]
};
}
return { isValid: true, errors: [] };
}
// ๐ฒ Generate cryptographically secure IDs
private generateSecureId(): string {
return `secure_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
// ๐ Hash password (placeholder for real hashing)
private async hashPassword(password: string): Promise<string> {
// ๐ง In real implementation, use bcrypt or argon2
return `hashed_${password}_with_salt`;
}
}
๐ฏ Try it yourself: Add a session timeout feature and brute-force attack protection!
๐งช Example 2: Security Test Suite
Letโs create comprehensive security tests:
// ๐งช Security test result interface
interface SecurityTestResult {
testName: string;
passed: boolean;
vulnerabilities: string[];
recommendations: string[];
severity: 'low' | 'medium' | 'high' | 'critical';
}
// ๐ Comprehensive security test suite
class OWASPSecurityTestSuite {
private system: SecureECommerceSystem;
constructor(system: SecureECommerceSystem) {
this.system = system;
}
// ๐งช Run complete OWASP security test suite
async runCompleteSecurityAudit(): Promise<SecurityTestResult[]> {
console.log("๐ Starting OWASP security audit...");
const results: SecurityTestResult[] = [];
// A1: Injection Testing
results.push(await this.testSqlInjectionPrevention());
// A2: Authentication Testing
results.push(await this.testAuthenticationSecurity());
// A3: Sensitive Data Exposure
results.push(await this.testDataEncryption());
// A7: Cross-Site Scripting (XSS)
results.push(await this.testXssPrevention());
console.log("โ
Security audit completed!");
this.generateSecurityReport(results);
return results;
}
// ๐ Test SQL injection prevention
private async testSqlInjectionPrevention(): Promise<SecurityTestResult> {
const maliciousInputs = [
"'; DROP TABLE users; --",
"admin' OR '1'='1",
"UNION SELECT * FROM sensitive_data"
];
const vulnerabilities: string[] = [];
for (const input of maliciousInputs) {
const validator = new SecureInputValidator();
const result = validator.validateSqlInput(input);
if (result.isValid) {
vulnerabilities.push(`๐จ SQL injection bypassed with: ${input}`);
}
}
return {
testName: "๐ก๏ธ SQL Injection Prevention",
passed: vulnerabilities.length === 0,
vulnerabilities,
recommendations: vulnerabilities.length > 0 ? [
"๐ง Implement parameterized queries",
"๐งน Add input sanitization",
"๐ก๏ธ Use ORM with built-in protection"
] : [],
severity: vulnerabilities.length > 0 ? 'critical' : 'low'
};
}
// ๐ Test authentication security
private async testAuthenticationSecurity(): Promise<SecurityTestResult> {
const vulnerabilities: string[] = [];
// ๐ Test weak password acceptance
const weakPasswords = ["123456", "password", "admin"];
for (const weakPassword of weakPasswords) {
const result = await this.system.registerUser("[email protected]", weakPassword);
if (result.success) {
vulnerabilities.push(`๐จ Weak password accepted: ${weakPassword}`);
}
}
return {
testName: "๐ Authentication Security",
passed: vulnerabilities.length === 0,
vulnerabilities,
recommendations: vulnerabilities.length > 0 ? [
"๐ Enforce strong password policies",
"๐ Implement account lockout after failed attempts",
"๐ Add two-factor authentication"
] : [],
severity: vulnerabilities.length > 0 ? 'high' : 'low'
};
}
// ๐ Test data encryption
private async testDataEncryption(): Promise<SecurityTestResult> {
const vulnerabilities: string[] = [];
// ๐ This would test if sensitive data is properly encrypted
// For demonstration, we'll check if passwords are hashed
const testUser = await this.system.registerUser("[email protected]", "SecurePass123!");
if (testUser.success) {
console.log("โ
Password hashing verified");
} else {
vulnerabilities.push("๐จ Password not properly secured");
}
return {
testName: "๐ Data Encryption",
passed: vulnerabilities.length === 0,
vulnerabilities,
recommendations: vulnerabilities.length > 0 ? [
"๐ก๏ธ Encrypt sensitive data at rest",
"๐ Use HTTPS for data in transit",
"๐ง Salt and hash passwords properly"
] : [],
severity: vulnerabilities.length > 0 ? 'critical' : 'low'
};
}
// ๐ซ Test XSS prevention
private async testXssPrevention(): Promise<SecurityTestResult> {
const xssPayloads = [
"<script>alert('XSS')</script>",
"<img src=x onerror=alert('XSS')>",
"javascript:alert('XSS')"
];
const vulnerabilities: string[] = [];
const validator = new SecureInputValidator();
for (const payload of xssPayloads) {
const result = validator.validateXssInput(payload);
if (result.isValid) {
vulnerabilities.push(`๐จ XSS payload not blocked: ${payload}`);
}
}
return {
testName: "๐ซ Cross-Site Scripting Prevention",
passed: vulnerabilities.length === 0,
vulnerabilities,
recommendations: vulnerabilities.length > 0 ? [
"๐งน Sanitize all user inputs",
"๐ก๏ธ Implement Content Security Policy",
"โจ Use proper output encoding"
] : [],
severity: vulnerabilities.length > 0 ? 'high' : 'low'
};
}
// ๐ Generate security report
private generateSecurityReport(results: SecurityTestResult[]): void {
console.log("\n๐ OWASP Security Audit Report");
console.log("================================");
const totalTests = results.length;
const passedTests = results.filter(r => r.passed).length;
const criticalIssues = results.filter(r => r.severity === 'critical').length;
console.log(`๐ Total Tests: ${totalTests}`);
console.log(`โ
Passed: ${passedTests}`);
console.log(`โ Failed: ${totalTests - passedTests}`);
console.log(`๐จ Critical Issues: ${criticalIssues}`);
if (criticalIssues === 0 && passedTests === totalTests) {
console.log("๐ All security tests passed! Your application is secure! ๐ก๏ธ");
} else {
console.log("โ ๏ธ Security improvements needed. Review recommendations above.");
}
}
}
๐ Advanced Security Testing
๐งโโ๏ธ Advanced Topic 1: Automated Security Scanning
When youโre ready to level up, try automated security testing:
// ๐ Automated security scanner
interface SecurityScanConfig {
enableStaticAnalysis: boolean;
enableDependencyCheck: boolean;
enablePenetrationTest: boolean;
scanDepth: 'shallow' | 'medium' | 'deep';
}
class AutomatedSecurityScanner {
private config: SecurityScanConfig;
constructor(config: SecurityScanConfig) {
this.config = config;
}
// ๐ค Run automated security scan
async performAutomatedScan(codebase: string[]): Promise<SecurityScanResult> {
console.log("๐ค Starting automated security scan...");
const findings: SecurityFinding[] = [];
if (this.config.enableStaticAnalysis) {
findings.push(...await this.runStaticAnalysis(codebase));
}
if (this.config.enableDependencyCheck) {
findings.push(...await this.checkDependencyVulnerabilities());
}
return {
timestamp: new Date(),
totalFindings: findings.length,
criticalFindings: findings.filter(f => f.severity === 'critical').length,
findings,
overallScore: this.calculateSecurityScore(findings)
};
}
// ๐ Static code analysis
private async runStaticAnalysis(codebase: string[]): Promise<SecurityFinding[]> {
const findings: SecurityFinding[] = [];
for (const file of codebase) {
// ๐จ Check for hardcoded secrets
if (file.includes('password') || file.includes('api_key')) {
findings.push({
type: 'hardcoded_secret',
severity: 'critical',
description: '๐จ Potential hardcoded secret detected',
recommendation: '๐ Use environment variables for secrets'
});
}
// โ ๏ธ Check for console.log in production
if (file.includes('console.log')) {
findings.push({
type: 'information_disclosure',
severity: 'medium',
description: 'โ ๏ธ Console logging in production code',
recommendation: '๐งน Remove debug statements from production'
});
}
}
return findings;
}
// ๐ฆ Check dependency vulnerabilities
private async checkDependencyVulnerabilities(): Promise<SecurityFinding[]> {
// ๐ This would integrate with npm audit or similar tools
return [
{
type: 'vulnerable_dependency',
severity: 'high',
description: '๐ฆ Outdated dependency with known vulnerabilities',
recommendation: 'โฌ๏ธ Update dependencies to latest secure versions'
}
];
}
// ๐ Calculate overall security score
private calculateSecurityScore(findings: SecurityFinding[]): number {
const weights = { critical: 10, high: 5, medium: 2, low: 1 };
const totalWeight = findings.reduce((sum, finding) => {
return sum + weights[finding.severity];
}, 0);
// ๐ Score from 0-100 (100 = perfect security)
return Math.max(0, 100 - totalWeight);
}
}
interface SecurityFinding {
type: string;
severity: 'low' | 'medium' | 'high' | 'critical';
description: string;
recommendation: string;
}
interface SecurityScanResult {
timestamp: Date;
totalFindings: number;
criticalFindings: number;
findings: SecurityFinding[];
overallScore: number;
}
๐๏ธ Advanced Topic 2: Security Testing CI/CD Integration
For the brave developers implementing DevSecOps:
// ๐ CI/CD Security Integration
class DevSecOpsIntegration {
// ๐ Run security tests in CI/CD pipeline
async runSecurityPipeline(): Promise<PipelineResult> {
console.log("๐ Starting DevSecOps security pipeline...");
const steps: PipelineStep[] = [
{ name: "๐ Static Analysis", status: 'pending' },
{ name: "๐งช Security Unit Tests", status: 'pending' },
{ name: "๐ฆ Dependency Audit", status: 'pending' },
{ name: "๐ท๏ธ Dynamic Security Testing", status: 'pending' },
{ name: "๐ก๏ธ Container Security Scan", status: 'pending' }
];
for (const step of steps) {
step.status = 'running';
console.log(`โณ Running: ${step.name}`);
// ๐งช Simulate security test execution
await this.simulateSecurityTest();
step.status = 'completed';
console.log(`โ
Completed: ${step.name}`);
}
return {
success: true,
steps,
securityScore: 95,
recommendations: [
"๐ง Update 2 dependencies with security patches",
"๐ก๏ธ Add rate limiting to API endpoints",
"๐ Implement additional input validation"
]
};
}
// โฑ๏ธ Simulate security test
private async simulateSecurityTest(): Promise<void> {
return new Promise(resolve => setTimeout(resolve, 1000));
}
}
interface PipelineStep {
name: string;
status: 'pending' | 'running' | 'completed' | 'failed';
}
interface PipelineResult {
success: boolean;
steps: PipelineStep[];
securityScore: number;
recommendations: string[];
}
โ ๏ธ Common Security Pitfalls and Solutions
๐ฑ Pitfall 1: Trusting User Input
// โ Wrong way - trusting user input!
function processUserData(userData: any): void {
// ๐ฅ Never do this - direct database query with user input!
const query = `SELECT * FROM users WHERE id = ${userData.id}`;
console.log("๐จ This is vulnerable to SQL injection!");
}
// โ
Correct way - validate and sanitize!
function processUserDataSecurely(userData: unknown): void {
// ๐ก๏ธ Type guard to ensure proper structure
if (!isValidUserData(userData)) {
throw new Error("โ ๏ธ Invalid user data format");
}
// ๐งน Sanitize the input
const validator = new SecureInputValidator();
const validationResult = validator.validateSqlInput(userData.id.toString());
if (!validationResult.isValid) {
throw new Error("๐จ Security validation failed");
}
// โ
Safe to process now
console.log(`โจ Processing secure user data for ID: ${validationResult.sanitizedInput}`);
}
function isValidUserData(data: unknown): data is { id: number; name: string } {
return typeof data === 'object' &&
data !== null &&
'id' in data &&
'name' in data &&
typeof (data as any).id === 'number';
}
๐คฏ Pitfall 2: Storing Sensitive Data Insecurely
// โ Dangerous - plaintext sensitive data!
interface UnsafeUser {
id: string;
email: string;
password: string; // ๐ฅ Never store passwords in plaintext!
creditCard: string; // ๐ฅ Never store unencrypted payment data!
}
// โ
Safe - proper data protection!
interface SecureUserData {
id: string;
email: string;
passwordHash: string; // ๐ Hashed with salt
encryptedPaymentToken?: string; // ๐ก๏ธ Encrypted or tokenized
lastLoginAttempt?: Date;
failedLoginAttempts: number;
}
class SecureUserManager {
// โ
Secure password handling
async createUser(email: string, password: string): Promise<SecureUserData> {
// ๐ง Hash password with salt (bcrypt recommended)
const passwordHash = await this.secureHashPassword(password);
return {
id: this.generateSecureId(),
email,
passwordHash,
failedLoginAttempts: 0
};
}
// ๐ Secure password verification
async verifyPassword(user: SecureUserData, password: string): Promise<boolean> {
// ๐ Compare with hashed password
return await this.compareHashedPassword(password, user.passwordHash);
}
private async secureHashPassword(password: string): Promise<string> {
// ๐ก๏ธ In real implementation, use bcrypt.hash()
return `secure_hash_${password}_with_salt_${Date.now()}`;
}
private async compareHashedPassword(password: string, hash: string): Promise<boolean> {
// ๐ In real implementation, use bcrypt.compare()
return hash.includes(password); // Simplified for demo
}
private generateSecureId(): string {
return `user_${Math.random().toString(36).substr(2, 16)}`;
}
}
๐ ๏ธ Best Practices
- ๐ฏ Validate Everything: Never trust user input - validate and sanitize all data!
- ๐ Use Type Guards: TypeScript type guards help catch security issues at compile time
- ๐ก๏ธ Encrypt Sensitive Data: Always encrypt passwords, payment data, and personal information
- ๐จ Implement Rate Limiting: Prevent brute force attacks with proper throttling
- โจ Keep Dependencies Updated: Regularly audit and update your npm packages
- ๐ง Use HTTPS Everywhere: Encrypt data in transit with TLS/SSL
- ๐ฏ Follow Principle of Least Privilege: Give users only the access they need
- ๐ Log Security Events: Monitor and log security-related activities
๐งช Hands-On Exercise
๐ฏ Challenge: Build a Secure API Authentication System
Create a comprehensive secure authentication system for a TypeScript API:
๐ Requirements:
- โ User registration with strong password validation
- ๐ Secure login with JWT tokens and rate limiting
- ๐ก๏ธ Session management with automatic timeout
- ๐จ Brute force protection with account lockout
- ๐ Security event logging
- ๐ Input validation and sanitization
- ๐จ Each endpoint needs proper security headers!
๐ Bonus Points:
- Add two-factor authentication (2FA)
- Implement OAuth integration
- Create security audit dashboard
- Add automated penetration testing
๐ก Solution
๐ Click to see solution
// ๐ฏ Our comprehensive secure authentication system!
interface SecureAuthUser {
id: string;
email: string;
passwordHash: string;
isEmailVerified: boolean;
failedLoginAttempts: number;
lastFailedLogin?: Date;
accountLockedUntil?: Date;
twoFactorSecret?: string;
securityEvents: SecurityEvent[];
}
interface SecurityEvent {
type: 'login' | 'logout' | 'failed_login' | 'password_change' | 'suspicious_activity';
timestamp: Date;
ipAddress: string;
userAgent: string;
success: boolean;
}
interface JWTPayload {
userId: string;
email: string;
iat: number;
exp: number;
}
class SecureAuthenticationSystem {
private users: Map<string, SecureAuthUser> = new Map();
private rateLimiter: Map<string, { attempts: number; resetTime: Date }> = new Map();
private securityLogger: SecurityLogger;
constructor() {
this.securityLogger = new SecurityLogger();
}
// ๐ Secure user registration
async registerUser(email: string, password: string, ipAddress: string): Promise<AuthResult> {
try {
// ๐ Validate input
const emailValidation = this.validateEmail(email);
if (!emailValidation.isValid) {
return { success: false, errors: emailValidation.errors };
}
const passwordValidation = this.validatePasswordStrength(password);
if (!passwordValidation.isValid) {
return { success: false, errors: passwordValidation.errors };
}
// ๐ Check if user already exists
const existingUser = Array.from(this.users.values()).find(u => u.email === email);
if (existingUser) {
return { success: false, errors: ["๐จ User already exists"] };
}
// ๐ Create secure user
const user: SecureAuthUser = {
id: this.generateSecureId(),
email: email.toLowerCase().trim(),
passwordHash: await this.hashPassword(password),
isEmailVerified: false,
failedLoginAttempts: 0,
securityEvents: []
};
this.users.set(user.id, user);
// ๐ Log security event
this.securityLogger.logEvent({
type: 'registration',
userId: user.id,
ipAddress,
timestamp: new Date(),
success: true
});
console.log(`โ
User registered securely: ${user.email}`);
return { success: true, userId: user.id };
} catch (error) {
console.error("๐จ Registration error:", error);
return { success: false, errors: ["โ Registration failed"] };
}
}
// ๐ Secure login with rate limiting
async login(email: string, password: string, ipAddress: string, userAgent: string): Promise<AuthResult> {
try {
// ๐ฆ Check rate limiting
if (!this.checkRateLimit(ipAddress)) {
this.securityLogger.logEvent({
type: 'rate_limit_exceeded',
ipAddress,
timestamp: new Date(),
success: false
});
return { success: false, errors: ["โฐ Too many login attempts. Please try again later."] };
}
// ๐ Find user
const user = Array.from(this.users.values()).find(u => u.email === email.toLowerCase());
if (!user) {
this.incrementRateLimit(ipAddress);
return { success: false, errors: ["โ Invalid credentials"] };
}
// ๐ Check if account is locked
if (this.isAccountLocked(user)) {
this.securityLogger.logEvent({
type: 'login_attempt_locked_account',
userId: user.id,
ipAddress,
timestamp: new Date(),
success: false
});
return { success: false, errors: ["๐ Account is temporarily locked due to suspicious activity"] };
}
// ๐ Verify password
const isPasswordValid = await this.verifyPassword(password, user.passwordHash);
if (!isPasswordValid) {
// ๐ Increment failed attempts
user.failedLoginAttempts++;
user.lastFailedLogin = new Date();
// ๐ Lock account after 5 failed attempts
if (user.failedLoginAttempts >= 5) {
user.accountLockedUntil = new Date(Date.now() + 30 * 60 * 1000); // 30 minutes
}
this.incrementRateLimit(ipAddress);
this.securityLogger.logEvent({
type: 'failed_login',
userId: user.id,
ipAddress,
userAgent,
timestamp: new Date(),
success: false
});
return { success: false, errors: ["โ Invalid credentials"] };
}
// โ
Successful login - reset counters
user.failedLoginAttempts = 0;
delete user.accountLockedUntil;
this.resetRateLimit(ipAddress);
// ๐ซ Generate JWT token
const token = this.generateJWTToken(user);
// ๐ Log successful login
this.securityLogger.logEvent({
type: 'successful_login',
userId: user.id,
ipAddress,
userAgent,
timestamp: new Date(),
success: true
});
console.log(`โ
User logged in: ${user.email}`);
return { success: true, token, userId: user.id };
} catch (error) {
console.error("๐จ Login error:", error);
return { success: false, errors: ["โ Login failed"] };
}
}
// ๐ซ Generate JWT token
private generateJWTToken(user: SecureAuthUser): string {
const payload: JWTPayload = {
userId: user.id,
email: user.email,
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + (60 * 60) // 1 hour expiry
};
// ๐ In real implementation, use jsonwebtoken library
return `jwt.${btoa(JSON.stringify(payload))}.signature`;
}
// ๐ Verify JWT token
verifyToken(token: string): { valid: boolean; payload?: JWTPayload } {
try {
// ๐ Parse token (simplified for demo)
const parts = token.split('.');
if (parts.length !== 3) {
return { valid: false };
}
const payload = JSON.parse(atob(parts[1])) as JWTPayload;
// โฐ Check expiry
if (payload.exp < Math.floor(Date.now() / 1000)) {
return { valid: false };
}
return { valid: true, payload };
} catch {
return { valid: false };
}
}
// ๐ฆ Rate limiting implementation
private checkRateLimit(ipAddress: string): boolean {
const limit = this.rateLimiter.get(ipAddress);
if (!limit) {
return true;
}
if (new Date() > limit.resetTime) {
this.rateLimiter.delete(ipAddress);
return true;
}
return limit.attempts < 10; // Max 10 attempts per hour
}
private incrementRateLimit(ipAddress: string): void {
const existing = this.rateLimiter.get(ipAddress);
const resetTime = new Date(Date.now() + 60 * 60 * 1000); // 1 hour
if (existing) {
existing.attempts++;
} else {
this.rateLimiter.set(ipAddress, { attempts: 1, resetTime });
}
}
private resetRateLimit(ipAddress: string): void {
this.rateLimiter.delete(ipAddress);
}
// ๐ Check if account is locked
private isAccountLocked(user: SecureAuthUser): boolean {
if (!user.accountLockedUntil) {
return false;
}
if (new Date() > user.accountLockedUntil) {
delete user.accountLockedUntil; // Unlock account
return false;
}
return true;
}
// ๐ Password utilities
private async hashPassword(password: string): Promise<string> {
// ๐ก๏ธ In real implementation, use bcrypt
return `hashed_${password}_${Date.now()}`;
}
private async verifyPassword(password: string, hash: string): Promise<boolean> {
// ๐ In real implementation, use bcrypt.compare
return hash.includes(password);
}
// ๐ก๏ธ Validation utilities
private validateEmail(email: string): ValidationResult {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return {
isValid: emailRegex.test(email),
errors: emailRegex.test(email) ? [] : ["๐ง Invalid email format"]
};
}
private validatePasswordStrength(password: string): ValidationResult {
const errors: string[] = [];
if (password.length < 8) errors.push("๐ Password must be at least 8 characters");
if (!/[A-Z]/.test(password)) errors.push("๐ Password must contain uppercase letters");
if (!/[a-z]/.test(password)) errors.push("๐ Password must contain lowercase letters");
if (!/[0-9]/.test(password)) errors.push("๐ Password must contain numbers");
if (!/[!@#$%^&*]/.test(password)) errors.push("๐ Password must contain special characters");
return { isValid: errors.length === 0, errors };
}
private generateSecureId(): string {
return `user_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
}
// ๐ Security event logger
class SecurityLogger {
private events: SecurityEvent[] = [];
logEvent(event: Omit<SecurityEvent, 'timestamp'> & { timestamp: Date }): void {
this.events.push(event as SecurityEvent);
console.log(`๐ Security Event: ${event.type} - ${event.success ? 'โ
' : 'โ'}`);
}
getSecurityReport(): SecurityReport {
const last24Hours = this.events.filter(e =>
e.timestamp > new Date(Date.now() - 24 * 60 * 60 * 1000)
);
return {
totalEvents: this.events.length,
last24Hours: last24Hours.length,
failedLogins: this.events.filter(e => e.type === 'failed_login').length,
suspiciousActivity: this.events.filter(e => e.type === 'suspicious_activity').length
};
}
}
interface AuthResult {
success: boolean;
token?: string;
userId?: string;
errors?: string[];
}
interface SecurityReport {
totalEvents: number;
last24Hours: number;
failedLogins: number;
suspiciousActivity: number;
}
// ๐ฎ Test the secure authentication system!
const authSystem = new SecureAuthenticationSystem();
// ๐ Register a user
authSystem.registerUser("[email protected]", "SecurePass123!", "192.168.1.1");
// ๐ Login
authSystem.login("[email protected]", "SecurePass123!", "192.168.1.1", "Mozilla/5.0...");
๐ Key Takeaways
Youโve learned so much about OWASP security testing! Hereโs what you can now do:
- โ Implement OWASP principles with confidence ๐ช
- โ Prevent common vulnerabilities like injection attacks ๐ก๏ธ
- โ Build secure authentication systems in real projects ๐ฏ
- โ Test for security issues like a pro ๐
- โ Create amazing secure applications with TypeScript! ๐
Remember: Security is not a feature, itโs a foundation! Itโs here to protect your users and your business. ๐ค
๐ค Next Steps
Congratulations! ๐ Youโve mastered OWASP security testing principles!
Hereโs what to do next:
- ๐ป Practice implementing the security testing patterns above
- ๐๏ธ Build a secure application using OWASP guidelines
- ๐ Move on to our next tutorial: Performance Testing & Load Testing
- ๐ Share your security knowledge with other developers!
Remember: Every security expert was once a beginner. Keep coding securely, keep learning, and most importantly, protect your users! ๐ก๏ธ
Happy secure coding! ๐๐โจ