Security Monitoring & Auditing
Audit logging, security monitoring, and threat detection for Smart Shelf.
Security Monitoring & Auditing
This section covers comprehensive security monitoring, audit logging, and threat detection mechanisms in Smart Shelf.
Audit Logging System
Audit Event Structure
// lib/audit/logger.ts
export interface AuditEvent {
action: string;
resource: string;
resourceId?: string;
userId: string;
ipAddress?: string;
userAgent?: string;
details?: any;
timestamp: Date;
}
export async function logAuditEvent(event: AuditEvent): Promise<void> {
const supabase = createServiceRoleClient();
try {
await supabase.from('audit_logs').insert({
action: event.action,
resource: event.resource,
resource_id: event.resourceId,
user_id: event.userId,
ip_address: event.ipAddress,
user_agent: event.userAgent,
details: event.details,
created_at: event.timestamp.toISOString(),
});
} catch (error) {
// Log to external service if database is unavailable
console.error('Audit logging failed:', error);
}
}
Automatic Audit Middleware
// Middleware for automatic audit logging
export function withAuditLog(action: string, resource: string) {
return function(handler: (req: NextRequest, user: User) => Promise<NextResponse>) {
return async function(req: NextRequest) {
const user = await validateAuth(req);
try {
const response = await handler(req, user);
// Log successful action
await logAuditEvent({
action,
resource,
userId: user.id,
ipAddress: req.headers.get('x-forwarded-for') || req.ip,
userAgent: req.headers.get('user-agent'),
timestamp: new Date(),
});
return response;
} catch (error) {
// Log failed action
await logAuditEvent({
action: `${action}_failed`,
resource,
userId: user.id,
ipAddress: req.headers.get('x-forwarded-for') || req.ip,
userAgent: req.headers.get('user-agent'),
details: { error: error.message },
timestamp: new Date(),
});
throw error;
}
};
};
}
// Usage example
export const POST = withAuditLog('create', 'product')(async (req, user) => {
// Create product logic
});
Security Headers and Protection
Security Headers Implementation
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const response = NextResponse.next();
// 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('X-XSS-Protection', '1; mode=block');
// Content Security Policy
const csp = [
"default-src 'self'",
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net",
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
"font-src 'self' https://fonts.gstatic.com",
"img-src 'self' data: https:",
"connect-src 'self' https://*.supabase.co wss://*.supabase.co",
"object-src 'none'",
"base-uri 'self'",
"form-action 'self'",
"frame-ancestors 'none'",
].join('; ');
response.headers.set('Content-Security-Policy', csp);
return response;
}
CSRF Protection
// CSRF Protection for state-changing requests
if (['POST', 'PUT', 'DELETE', 'PATCH'].includes(request.method)) {
const origin = request.headers.get('origin');
const host = request.headers.get('host');
if (!origin || !host || !origin.includes(host)) {
return NextResponse.json(
{ error: 'Invalid origin' },
{ status: 403 }
);
}
}
Rate Limiting and Abuse Prevention
API Rate Limiting
// lib/security/rate-limit.ts
import { Redis } from 'ioredis';
const redis = new Redis(process.env.REDIS_URL!);
interface RateLimit {
windowMs: number; // Time window in milliseconds
maxRequests: number; // Maximum requests per window
}
const RATE_LIMITS: Record<string, RateLimit> = {
login: { windowMs: 15 * 60 * 1000, maxRequests: 5 }, // 5 attempts per 15 minutes
api: { windowMs: 60 * 1000, maxRequests: 100 }, // 100 requests per minute
upload: { windowMs: 60 * 1000, maxRequests: 10 }, // 10 uploads per minute
};
export async function checkRateLimit(
identifier: string,
limitType: keyof typeof RATE_LIMITS
): Promise<{ allowed: boolean; remaining: number; resetTime: number }> {
const limit = RATE_LIMITS[limitType];
const key = `rate_limit:${limitType}:${identifier}`;
const current = await redis.get(key);
const requests = current ? parseInt(current) : 0;
if (requests >= limit.maxRequests) {
const ttl = await redis.ttl(key);
return {
allowed: false,
remaining: 0,
resetTime: Date.now() + (ttl * 1000),
};
}
// Increment counter
const pipeline = redis.pipeline();
pipeline.incr(key);
pipeline.expire(key, Math.ceil(limit.windowMs / 1000));
await pipeline.exec();
return {
allowed: true,
remaining: limit.maxRequests - requests - 1,
resetTime: Date.now() + limit.windowMs,
};
}
// Rate limiting middleware
export function withRateLimit(limitType: keyof typeof RATE_LIMITS) {
return function(handler: Function) {
return async function(req: NextRequest) {
const identifier = req.headers.get('x-forwarded-for') || req.ip || 'unknown';
const rateLimit = await checkRateLimit(identifier, limitType);
if (!rateLimit.allowed) {
return NextResponse.json(
{ error: 'Rate limit exceeded' },
{
status: 429,
headers: {
'Retry-After': Math.ceil((rateLimit.resetTime - Date.now()) / 1000).toString(),
'X-RateLimit-Remaining': '0',
'X-RateLimit-Reset': rateLimit.resetTime.toString(),
}
}
);
}
const response = await handler(req);
// Add rate limit headers to successful responses
response.headers.set('X-RateLimit-Remaining', rateLimit.remaining.toString());
response.headers.set('X-RateLimit-Reset', rateLimit.resetTime.toString());
return response;
};
};
}
Threat Detection and Monitoring
Suspicious Activity Detection
// lib/security/threat-detection.ts
export interface SecurityEvent {
type: 'failed_login' | 'suspicious_access' | 'data_breach_attempt' | 'privilege_escalation';
severity: 'low' | 'medium' | 'high' | 'critical';
userId?: string;
ipAddress: string;
userAgent?: string;
details: any;
timestamp: Date;
}
export async function detectThreats(event: SecurityEvent): Promise<void> {
// Log security event
await logSecurityEvent(event);
// Check for patterns
switch (event.type) {
case 'failed_login':
await checkFailedLoginPattern(event);
break;
case 'suspicious_access':
await checkAccessPattern(event);
break;
case 'privilege_escalation':
await alertAdministrators(event);
break;
}
}
async function checkFailedLoginPattern(event: SecurityEvent): Promise<void> {
const recentFailures = await getRecentSecurityEvents(
event.ipAddress,
'failed_login',
15 * 60 * 1000 // 15 minutes
);
if (recentFailures.length >= 5) {
// Block IP temporarily
await blockIpAddress(event.ipAddress, 60 * 60 * 1000); // 1 hour
// Alert administrators
await alertAdministrators({
...event,
type: 'failed_login',
severity: 'high',
details: {
...event.details,
pattern: 'brute_force_attempt',
failureCount: recentFailures.length,
},
});
}
}
async function alertAdministrators(event: SecurityEvent): Promise<void> {
// Send alert to administrators
const admins = await getAdministrators();
for (const admin of admins) {
await sendSecurityAlert(admin.email, {
subject: `Security Alert: ${event.type}`,
priority: event.severity,
details: event,
});
}
// Log to external monitoring service
await logToMonitoringService(event);
}
Real-time Monitoring Dashboard
// lib/monitoring/dashboard.ts
export async function getSecurityMetrics(timeRange: string) {
const supabase = createServiceRoleClient();
const [
failedLogins,
suspiciousActivities,
blockedIps,
auditEvents,
] = await Promise.all([
supabase
.from('security_events')
.select('count(*)')
.eq('type', 'failed_login')
.gte('created_at', getTimeRangeStart(timeRange)),
supabase
.from('security_events')
.select('count(*)')
.eq('type', 'suspicious_access')
.gte('created_at', getTimeRangeStart(timeRange)),
supabase
.from('blocked_ips')
.select('count(*)')
.eq('is_active', true),
supabase
.from('audit_logs')
.select('action, count(*)')
.gte('created_at', getTimeRangeStart(timeRange))
.group('action'),
]);
return {
failedLogins: failedLogins.data?.[0]?.count || 0,
suspiciousActivities: suspiciousActivities.data?.[0]?.count || 0,
blockedIps: blockedIps.data?.[0]?.count || 0,
auditEvents: auditEvents.data || [],
generatedAt: new Date().toISOString(),
};
}
Incident Response
Automated Response Actions
// lib/security/incident-response.ts
export async function handleSecurityIncident(incident: SecurityEvent): Promise<void> {
switch (incident.severity) {
case 'critical':
await executeCriticalResponse(incident);
break;
case 'high':
await executeHighSeverityResponse(incident);
break;
case 'medium':
await executeMediumSeverityResponse(incident);
break;
case 'low':
await logIncident(incident);
break;
}
}
async function executeCriticalResponse(incident: SecurityEvent): Promise<void> {
// Immediate actions for critical incidents
await Promise.all([
// Alert all administrators immediately
alertAdministrators(incident),
// Block source IP if applicable
incident.ipAddress && await blockIpAddress(incident.ipAddress),
// Disable affected user account if applicable
incident.userId && await disableUserAccount(incident.userId, 'security_incident'),
// Log to external security service
logToSecurityService(incident),
// Trigger incident response workflow
triggerIncidentWorkflow(incident),
]);
}
Security Monitoring Best Practices
Monitoring Checklist
- All authentication attempts logged
- Failed login attempts monitored and alerted
- Unusual access patterns detected
- Rate limiting implemented on all endpoints
- Security headers properly configured
- Real-time monitoring dashboard available
- Incident response procedures documented
- Regular security metrics reviewed
Alert Configuration
- Critical: Immediate notification (SMS, email, Slack)
- High: Notification within 15 minutes
- Medium: Daily digest report
- Low: Weekly summary report
This monitoring and auditing system provides comprehensive security oversight while enabling rapid response to potential threats and security incidents.