Security Package (@schwab/security)
Overview
The @schwab/security package provides a comprehensive security library for the Charles Schwab monorepo, implementing content security policies, bot detection mechanisms, secure cookie management, and various authentication utilities. It ensures consistent security practices across all applications while providing robust protection against common web vulnerabilities.
Architecture
Core Security Features
1. Content Security Policy (CSP)
Comprehensive CSP Configuration:
// src/content-security-policy/ContentSecurityPolicy.ts
export const ContentSecurityPolicy = {
'default-src': ["'self'"],
'script-src': [
"'self'",
"'unsafe-inline'",
"'unsafe-eval'",
"https://schwab.com",
"https://*.schwab.com",
"https://assets.schwab.com",
"https://www.google-analytics.com",
"https://www.googletagmanager.com"
],
'style-src': [
"'self'",
"'unsafe-inline'",
"https://fonts.googleapis.com",
"https://assets.schwab.com"
],
'img-src': [
"'self'",
"data:",
"https:",
"https://*.schwab.com",
"https://www.google-analytics.com"
],
'font-src': [
"'self'",
"https://fonts.gstatic.com",
"https://assets.schwab.com"
],
'connect-src': [
"'self'",
"https://*.schwab.com",
"https://api.schwab.com",
"https://www.google-analytics.com"
],
'media-src': ["'self'", "https://*.schwab.com"],
'object-src': ["'none'"],
'base-uri': ["'self'"],
'form-action': ["'self'", "https://*.schwab.com"],
'frame-ancestors': ["'none'"],
'upgrade-insecure-requests': []
};
2. Bot Detection System
Advanced Bot Detection and Mitigation:
// src/bot-check/config/route.config.ts
export const CheckBotIdConfigs = {
enabledRoutes: [
'/account-opening/*',
'/login',
'/registration/*',
'/contact-form',
'/lead-generation/*'
],
bypassRoutes: [
'/api/*',
'/health-check',
'/_next/*',
'/favicon.ico'
],
analysisConfig: {
checkUserAgent: true,
checkBehaviorPatterns: true,
checkRequestFrequency: true,
checkJavaScriptCapability: true,
checkMouseMovements: true
},
thresholds: {
suspiciousScore: 7,
blockingScore: 9,
maxRequestsPerMinute: 30
}
};
Bot Check Implementation:
// src/bot-check/handleCheckBotIdByMode.ts
import { ECheckBotIdFlagStates } from '@schwab/schema/native-enums/ECheckBotIdFlagStates';
export async function HandleCheckBotIdByMode(
request: NextRequest,
mode: ECheckBotIdFlagStates
): Promise<NextResponse | null> {
// Check if route requires bot protection
const requiresCheck = await IsBotCheckRoute(request.nextUrl.pathname);
if (!requiresCheck) return null;
switch (mode) {
case ECheckBotIdFlagStates.Enforcing:
return await enforceStrictBotCheck(request);
case ECheckBotIdFlagStates.Learning:
return await performLearningModeCheck(request);
case ECheckBotIdFlagStates.Disabled:
return null;
default:
return await performDefaultBotCheck(request);
}
}
3. Secure Cookie Management
Encrypted Cookie Utilities:
// src/secure-cookies/utilities/encryptCookie.ts
import { SignJWT } from 'jose';
export async function EncryptCookie<T>(
payload: T,
secret: string,
expirationHours: number = 24
): Promise<string> {
const secretKey = new TextEncoder().encode(secret);
const jwt = await new SignJWT(payload as any)
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime(GetExpirationTimestamp(expirationHours))
.setIssuer('schwab.com')
.setAudience('schwab-app')
.sign(secretKey);
return jwt;
}
// src/secure-cookies/utilities/decryptCookie.ts
import { jwtVerify } from 'jose';
export async function DecryptCookie<T>(
encryptedCookie: string,
secret: string
): Promise<T | null> {
try {
const secretKey = new TextEncoder().encode(secret);
const { payload } = await jwtVerify(encryptedCookie, secretKey, {
issuer: 'schwab.com',
audience: 'schwab-app',
});
return payload as T;
} catch (error) {
console.error('Cookie decryption failed:', error);
return null;
}
}
4. Bot Detection Functions
Core Detection Algorithms:
// src/bot-check/functions/runVercelCheckBotId.ts
export async function RunVercelCheckBotId(
request: NextRequest
): Promise<BotCheckResult> {
const analysisResults = await Promise.all([
analyzeUserAgent(request.headers.get('user-agent')),
analyzeRequestPatterns(request),
analyzeBehaviorSignals(request),
checkIPReputation(getClientIP(request))
]);
const suspicionScore = calculateSuspicionScore(analysisResults);
return {
isBot: suspicionScore >= CheckBotIdConfigs.thresholds.blockingScore,
suspicionScore,
details: analysisResults,
timestamp: new Date().toISOString()
};
}
// src/bot-check/functions/processBotCheckIdResults.ts
export function ProcessBotCheckIdResults(
result: BotCheckResult,
request: NextRequest
): NextResponse {
if (result.isBot) {
// Block suspected bot traffic
return new NextResponse('Access Denied', {
status: 403,
headers: {
'X-Bot-Check': 'blocked',
'X-Suspicion-Score': result.suspicionScore.toString()
}
});
}
// Allow legitimate traffic with tracking
const response = NextResponse.next();
response.headers.set('X-Bot-Check', 'passed');
response.headers.set('X-Suspicion-Score', result.suspicionScore.toString());
return response;
}
Authentication Security
1. Cookie Security Utilities
// Enhanced cookie security with proper flags
export function setSecureCookie(
response: NextResponse,
name: string,
value: string,
options: CookieOptions = {}
) {
const secureOptions = {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict' as const,
path: '/',
maxAge: 24 * 60 * 60, // 24 hours
...options
};
response.cookies.set(name, value, secureOptions);
}
export function clearSecureCookie(
response: NextResponse,
name: string
) {
response.cookies.delete(name);
}
2. Session Management
// Secure session token generation and validation
export async function generateSecureSessionToken(): Promise<string> {
const randomBytes = crypto.getRandomValues(new Uint8Array(32));
const token = Array.from(randomBytes, byte =>
byte.toString(16).padStart(2, '0')
).join('');
return token;
}
export async function validateSessionToken(
token: string,
secret: string
): Promise<boolean> {
try {
// Validate token format and signature
const isValid = await verifyTokenSignature(token, secret);
const isNotExpired = checkTokenExpiration(token);
return isValid && isNotExpired;
} catch (error) {
return false;
}
}
Security Middleware Integration
1. Next.js Middleware Integration
// middleware.ts integration example
import { HandleCheckBotIdByMode } from '@schwab/security/HandleCheckBotIdByMode';
import { ContentSecurityPolicy } from '@schwab/security/ContentSecurityPolicy';
export async function middleware(request: NextRequest) {
const response = NextResponse.next();
// Apply Content Security Policy
const cspHeader = Object.entries(ContentSecurityPolicy)
.map(([key, values]) => `${key} ${values.join(' ')}`)
.join('; ');
response.headers.set('Content-Security-Policy', cspHeader);
// Bot detection check
const botCheckResponse = await HandleCheckBotIdByMode(
request,
process.env.BOT_CHECK_MODE as ECheckBotIdFlagStates
);
if (botCheckResponse) {
return botCheckResponse;
}
// Security headers
response.headers.set('X-Frame-Options', 'DENY');
response.headers.set('X-Content-Type-Options', 'nosniff');
response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
response.headers.set('Permissions-Policy', 'geolocation=(), microphone=(), camera=()');
return response;
}
Testing and Development Tools
1. Test Cookie Generation
// src/bot-check/functions/__test_tools__/generateAndSetTestCookieData.ts
export async function GenerateAndSetTestCookieData(
scenario: 'legitimate' | 'suspicious' | 'bot',
response: NextResponse
): Promise<void> {
const testData = {
legitimate: {
suspicionScore: 2,
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
behaviorPattern: 'human'
},
suspicious: {
suspicionScore: 6,
userAgent: 'Mozilla/5.0 (compatible; Suspicious Bot)',
behaviorPattern: 'automated'
},
bot: {
suspicionScore: 10,
userAgent: 'Bot/1.0',
behaviorPattern: 'bot'
}
};
const encryptedCookie = await EncryptCookie(
testData[scenario],
process.env.BOT_CHECK_SECRET!
);
response.cookies.set('schwab-bot-check', encryptedCookie, {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 3600 // 1 hour for testing
});
}
2. Security Testing Framework
// Testing framework for security features
export class SecurityTestHelper {
static async simulateBotTraffic(requests: number = 100) {
const results = [];
for (let i = 0; i < requests; i++) {
const mockRequest = new Request('https://example.com/test', {
headers: {
'User-Agent': 'TestBot/1.0',
'X-Forwarded-For': `192.168.1.${i % 255}`
}
});
const result = await RunVercelCheckBotId(mockRequest as any);
results.push(result);
}
return results;
}
static validateCSPCompliance(response: Response): boolean {
const cspHeader = response.headers.get('Content-Security-Policy');
return cspHeader !== null && cspHeader.includes("default-src 'self'");
}
}
Performance and Monitoring
1. Security Metrics
export interface SecurityMetrics {
botDetectionRate: number;
falsePositiveRate: number;
averageResponseTime: number;
blockedRequests: number;
suspiciousRequests: number;
}
export class SecurityMonitor {
static async logSecurityEvent(
event: 'bot_detected' | 'suspicious_activity' | 'csrf_attempt',
details: Record<string, any>
) {
// Log to security monitoring system
console.log(`[SECURITY] ${event}:`, details);
// Send to external monitoring service if configured
if (process.env.SECURITY_MONITORING_ENDPOINT) {
await fetch(process.env.SECURITY_MONITORING_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ event, details, timestamp: Date.now() })
});
}
}
}
Configuration Management
1. Environment-based Security Configuration
export const SecurityConfig = {
production: {
botCheckMode: ECheckBotIdFlagStates.Enforcing,
strictCSP: true,
cookieSecure: true,
sessionTimeout: 30 * 60 * 1000, // 30 minutes
},
staging: {
botCheckMode: ECheckBotIdFlagStates.Learning,
strictCSP: true,
cookieSecure: true,
sessionTimeout: 60 * 60 * 1000, // 1 hour
},
development: {
botCheckMode: ECheckBotIdFlagStates.Disabled,
strictCSP: false,
cookieSecure: false,
sessionTimeout: 8 * 60 * 60 * 1000, // 8 hours
}
};
export function getSecurityConfig() {
const env = process.env.NODE_ENV || 'development';
return SecurityConfig[env] || SecurityConfig.development;
}
Error Handling and Logging
1. Security Error Management
export class SecurityError extends Error {
constructor(
message: string,
public code: string,
public severity: 'low' | 'medium' | 'high' | 'critical'
) {
super(message);
this.name = 'SecurityError';
}
}
export function handleSecurityError(error: SecurityError, context?: string) {
const logLevel = {
low: 'info',
medium: 'warn',
high: 'error',
critical: 'error'
}[error.severity];
console[logLevel](`[SECURITY ERROR] ${error.code}: ${error.message}`, {
context,
severity: error.severity,
timestamp: new Date().toISOString()
});
if (error.severity === 'critical') {
// Trigger immediate security alert
SecurityMonitor.logSecurityEvent('critical_security_error', {
code: error.code,
message: error.message,
context
});
}
}
Future Enhancements
Planned Security Improvements
- Advanced Threat Detection: ML-based behavioral analysis
- Zero-Trust Architecture: Enhanced verification for all requests
- Real-time Threat Intelligence: Integration with security feeds
- Automated Response: Intelligent threat mitigation
- Enhanced Monitoring: Comprehensive security dashboards
Compliance and Standards
- OWASP Top 10: Full compliance with latest security standards
- PCI DSS: Payment card industry data security standards
- SOX Compliance: Sarbanes-Oxley financial compliance
- GDPR/CCPA: Privacy regulation compliance
- Financial Industry Standards: Sector-specific security requirements
The Security package provides enterprise-grade security infrastructure that protects the Charles Schwab digital ecosystem from modern threats while maintaining optimal user experience. Its comprehensive approach to security ensures robust protection across all applications and services.