Features
Docs
CLI
Benchmarks
Examples

© 2024 MoroJs

Security Features

Built-in security features like CORS, Helmet, and rate limiting. For advanced security, integrate with middleware and third-party libraries.

Security That Just Works

Enable security features with one line.
CORS, Helmet, rate limiting, and input validation built-in.

It's This Simple

Enable security features with one line

typescript

1import { createApp } from '@morojs/moro';
2
3// Basic security setup (actual implementation)
4const app = createApp({
5  cors: true,        // Enable CORS
6  compression: true, // Enable gzip compression
7  helmet: true       // Enable security headers
8});

Why Security Matters

Without proper security, your API is vulnerable to attacks. With MoroJS, you get essential security features out of the box.

Traditional security setup requires multiple libraries and complex configuration. We handle that automatically.

Without Security

  • Vulnerable to common attacks
  • Manual security header management
  • Complex CORS configuration
  • No built-in rate limiting

With MoroJS

  • Built-in security headers (Helmet)
  • One-line CORS enablement
  • Automatic input validation
  • Per-route rate limiting

It's This Easy

Add validation and rate limiting to any route. That's it.

Input validation and rate limiting

typescript

1// Input validation with Zod (built-in)
2app.post('/users')
3  .body(z.object({
4    name: z.string().min(2).max(50),
5    email: z.string().email(),
6    password: z.string().min(8)
7  }))
8  .handler((req, res) => {
9    // Input is automatically validated and sanitized
10    const { name, email, password } = req.body;
11    return { success: true, data: { name, email } };
12  });
13
14// Rate limiting (chainable API)
15app.post('/auth/login')
16  .rateLimit({ requests: 5, window: 900000 }) // 5 attempts per 15 minutes
17  .handler((req, res) => {
18    return authenticateUser(req.body);
19  });

Why It Makes Sense

Protected

Security headers, CORS, and input validation. Secure by default.

Flexible

Built-in features plus extensibility. Add advanced security when needed.

Simple

One-line enablement. Automatic configuration. Zero setup.

How It Works

MoroJS includes basic security features out of the box. CORS, Helmet security headers, compression, and input validation are available with simple configuration. For advanced security features, integrate with middleware libraries and implement custom security measures.

Built-in Security Features

Basic Security Configuration

typescript

1import { createApp } from '@morojs/moro';
2
3// Basic security setup (actual implementation)
4const app = createApp({
5  cors: true,        // Enable CORS
6  compression: true, // Enable gzip compression
7  helmet: true       // Enable security headers
8});
9
10// Input validation with Zod (built-in)
11app.post('/users')
12  .body(z.object({
13    name: z.string().min(2).max(50),
14    email: z.string().email(),
15    password: z.string().min(8)
16  }))
17  .handler((req, res) => {
18    // Input is automatically validated and sanitized
19    const { name, email, password } = req.body;
20    
21    // Hash password before storing (use bcrypt library)
22    const hashedPassword = hashPassword(password);
23    
24    const user = createUser({
25      name,
26      email,
27      password: hashedPassword
28    });
29    
30    return { success: true, data: user };
31  });
32
33// Rate limiting (chainable API)
34app.post('/auth/login')
35  .rateLimit({ requests: 5, window: 900000 }) // 5 attempts per 15 minutes
36  .handler((req, res) => {
37    return authenticateUser(req.body);
38  });

What's Included

  • • CORS support (simple boolean flag)
  • • Helmet security headers
  • • Gzip compression
  • • Input validation with Zod
  • • Rate limiting (per-route)
  • • WebSocket support

Additional Security

For advanced security, integrate these libraries:

  • bcrypt - Password hashing
  • jsonwebtoken - JWT authentication
  • express-rate-limit - Advanced rate limiting
  • express-validator - Additional validation
  • passport - Authentication strategies

Advanced Security Configuration

For advanced security features, you can configure comprehensive security headers, implement authentication and authorization, set up rate limiting and DDoS protection, and add security monitoring.

Comprehensive Security Headers

typescript

1import { createApp } from '@morojs/moro';
2
3const app = createApp({
4  security: {
5    helmet: {
6      // Content Security Policy
7      contentSecurityPolicy: {
8        directives: {
9          defaultSrc: ["'self'"],
10          scriptSrc: ["'self'", "'unsafe-inline'", "https://cdn.example.com"],
11          styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
12          imgSrc: ["'self'", "data:", "https:"],
13          connectSrc: ["'self'", "https://api.example.com"],
14          fontSrc: ["'self'", "https://fonts.gstatic.com"],
15          objectSrc: ["'none'"],
16          mediaSrc: ["'self'"],
17          frameSrc: ["'none'"],
18        },
19        reportOnly: false, // Set to true for testing
20        reportUri: '/csp-report'
21      },
22      
23      // HTTP Strict Transport Security
24      hsts: {
25        maxAge: 31536000, // 1 year
26        includeSubDomains: true,
27        preload: true
28      },
29      
30      // X-Frame-Options
31      frameguard: {
32        action: 'deny' // or 'sameorigin'
33      },
34      
35      // X-Content-Type-Options
36      noSniff: true,
37      
38      // X-XSS-Protection
39      xssFilter: true,
40      
41      // Referrer Policy
42      referrerPolicy: { policy: "strict-origin-when-cross-origin" },
43      
44      // Hide X-Powered-By header
45      hidePoweredBy: true,
46      
47      // DNS Prefetch Control
48      dnsPrefetchControl: { allow: false },
49      
50      // IE No Open
51      ieNoOpen: true,
52      
53      // Cross-Origin Embedder Policy
54      crossOriginEmbedderPolicy: true,
55      
56      // Cross-Origin Opener Policy
57      crossOriginOpenerPolicy: { policy: "same-origin" },
58      
59      // Cross-Origin Resource Policy
60      crossOriginResourcePolicy: { policy: "cross-origin" },
61      
62      // Origin Agent Cluster
63      originAgentCluster: true,
64      
65      // Permitted Cross-Domain Policies
66      permittedCrossDomainPolicies: false
67    }
68  }
69});

Environment-Specific Security

typescript

1const getSecurityConfig = () => {
2  const isProd = process.env.NODE_ENV === 'production';
3  
4  return {
5    helmet: {
6      contentSecurityPolicy: {
7        directives: {
8          defaultSrc: ["'self'"],
9          scriptSrc: isProd 
10            ? ["'self'"] 
11            : ["'self'", "'unsafe-inline'", "'unsafe-eval'"],
12          styleSrc: ["'self'", "'unsafe-inline'"],
13          imgSrc: ["'self'", "data:", "https:"],
14          connectSrc: isProd
15            ? ["'self'", "https://api.example.com"]
16            : ["'self'", "http://localhost:*", "ws://localhost:*"]
17        },
18        reportOnly: !isProd
19      },
20      hsts: isProd ? {
21        maxAge: 31536000,
22        includeSubDomains: true,
23        preload: true
24      } : false
25    }
26  };
27};
28
29const app = createApp({
30  security: getSecurityConfig()
31});

Authentication & Authorization

JWT Authentication Middleware

typescript

1import { jwt, requireAuth, requireRole } from '@morojs/moro/auth';
2
3// JWT configuration
4const app = createApp({
5  auth: {
6    jwt: {
7      secret: process.env.JWT_SECRET,
8      algorithm: 'HS256',
9      expiresIn: '1h',
10      issuer: 'myapp.com',
11      audience: 'myapp-users'
12    }
13  }
14});
15
16// JWT validation middleware
17const jwtAuth = jwt({
18  secret: process.env.JWT_SECRET,
19  algorithms: ['HS256'],
20  credentialsRequired: true,
21  getToken: (req) => {
22    // Extract from Authorization header
23    const authHeader = req.headers.authorization;
24    if (authHeader && authHeader.startsWith('Bearer ')) {
25      return authHeader.substring(7);
26    }
27    
28    // Or from cookie
29    return req.cookies?.token;
30  }
31});
32
33// Protected routes
34app.get('/profile', {
35  middleware: [jwtAuth],
36  handler: ({ context }) => {
37    const user = context.user; // Populated by JWT middleware
38    return {
39      id: user.id,
40      email: user.email,
41      name: user.name
42    };
43  }
44});
45
46// Role-based access control
47app.post('/admin/users', {
48  middleware: [
49    jwtAuth,
50    requireRole(['admin', 'super-admin'])
51  ],
52  handler: createUser
53});
54
55// Permission-based access control
56app.delete('/posts/:id', {
57  middleware: [
58    jwtAuth,
59    requirePermission('posts:delete')
60  ],
61  handler: deletePost
62});

OAuth 2.0 / OpenID Connect

typescript

1import { oauth } from '@morojs/moro/auth';
2
3// OAuth configuration
4const oauthConfig = {
5  google: {
6    clientId: process.env.GOOGLE_CLIENT_ID,
7    clientSecret: process.env.GOOGLE_CLIENT_SECRET,
8    redirectUri: 'https://myapp.com/auth/google/callback',
9    scopes: ['openid', 'profile', 'email']
10  },
11  github: {
12    clientId: process.env.GITHUB_CLIENT_ID,
13    clientSecret: process.env.GITHUB_CLIENT_SECRET,
14    redirectUri: 'https://myapp.com/auth/github/callback',
15    scopes: ['user:email']
16  }
17};
18
19// OAuth routes
20app.get('/auth/:provider', {
21  handler: ({ params }) => {
22    const { provider } = params;
23    const config = oauthConfig[provider];
24    
25    if (!config) {
26      return { error: 'Unsupported provider' };
27    }
28    
29    const authUrl = oauth.getAuthorizationUrl(provider, config);
30    return { redirect: authUrl };
31  }
32});
33
34app.get('/auth/:provider/callback', {
35  handler: async ({ params, query }) => {
36    const { provider } = params;
37    const { code, state } = query;
38    
39    try {
40      const tokenData = await oauth.exchangeCodeForToken(provider, code);
41      const userInfo = await oauth.getUserInfo(provider, tokenData.access_token);
42      
43      // Create or update user in database
44      const user = await createOrUpdateUser(userInfo);
45      
46      // Generate JWT token
47      const jwt = await generateJWT(user);
48      
49      return {
50        success: true,
51        token: jwt,
52        user: {
53          id: user.id,
54          email: user.email,
55          name: user.name
56        }
57      };
58    } catch (error) {
59      return { error: 'Authentication failed' };
60    }
61  }
62});

Rate Limiting & DDoS Protection

Advanced Rate Limiting

typescript

1import { rateLimit } from '@morojs/moro/middleware';
2
3// Global rate limiting
4app.use(rateLimit({
5  windowMs: 15 * 60 * 1000, // 15 minutes
6  max: 1000, // Limit each IP to 1000 requests per windowMs
7  message: {
8    error: 'Too many requests from this IP, please try again later.',
9    retryAfter: 900 // seconds
10  },
11  
12  // Custom key generator
13  keyGenerator: (req) => {
14    // Rate limit by user ID if authenticated, otherwise by IP
15    return req.user?.id || req.ip;
16  },
17  
18  // Skip certain requests
19  skip: (req) => {
20    return req.path === '/health' || req.path === '/metrics';
21  },
22  
23  // Custom handler for rate limit exceeded
24  handler: (req, res) => {
25    res.status(429).json({
26      error: 'Rate limit exceeded',
27      retryAfter: Math.round(req.rateLimit.resetTime / 1000),
28      limit: req.rateLimit.limit,
29      current: req.rateLimit.current,
30      remaining: req.rateLimit.remaining
31    });
32  },
33  
34  // Store for distributed rate limiting
35  store: new RedisStore({
36    client: redis,
37    prefix: 'rl:'
38  })
39}));
40
41// API-specific rate limiting
42app.use('/api/', rateLimit({
43  windowMs: 1 * 60 * 1000, // 1 minute
44  max: 100, // 100 requests per minute for API
45  standardHeaders: true,
46  legacyHeaders: false
47}));
48
49// Strict rate limiting for authentication endpoints
50app.use('/auth/', rateLimit({
51  windowMs: 15 * 60 * 1000, // 15 minutes
52  max: 5, // Only 5 login attempts per 15 minutes
53  skipSuccessfulRequests: true,
54  
55  // Progressive delays
56  onLimitReached: (req, res, options) => {
57    // Log security event
58    logger.warn('Rate limit exceeded for auth endpoint', {
59      ip: req.ip,
60      userAgent: req.get('User-Agent'),
61      path: req.path
62    });
63  }
64}));

DDoS Protection

typescript

1import { ddosProtection } from '@morojs/moro/security';
2
3// DDoS protection middleware
4app.use(ddosProtection({
5  // Maximum number of connections per IP
6  burst: 10,
7  limit: 15,
8  
9  // Time window for connection tracking
10  maxconnections: 100,
11  maxrequestspersecond: 20,
12  
13  // Whitelist trusted IPs
14  whitelist: [
15    '127.0.0.1',
16    '::1',
17    // Add your trusted IPs/ranges
18    '10.0.0.0/8',
19    '172.16.0.0/12',
20    '192.168.0.0/16'
21  ],
22  
23  // Blacklist known bad IPs
24  blacklist: [
25    // IPs will be added dynamically
26  ],
27  
28  // Response for blocked requests
29  errorData: {
30    error: 'Request blocked due to suspicious activity',
31    code: 'DDOS_PROTECTION'
32  },
33  
34  // Callback for blocked requests
35  onDenial: (req) => {
36    logger.warn('DDoS protection triggered', {
37      ip: req.ip,
38      userAgent: req.get('User-Agent'),
39      path: req.path,
40      timestamp: new Date().toISOString()
41    });
42    
43    // Optionally add to blacklist
44    if (req.ddos.weight > 50) {
45      ddosProtection.addToBlacklist(req.ip, 3600); // 1 hour
46    }
47  }
48}));

Input Validation & Sanitization

Comprehensive Input Validation

typescript

1import { z } from 'zod';
2import { sanitize } from '@morojs/moro/security';
3
4// Custom sanitization schemas
5const SanitizedString = z.string().transform((val) => {
6  // Remove HTML tags and dangerous characters
7  return sanitize.html(val, {
8    allowedTags: [],
9    allowedAttributes: {}
10  });
11});
12
13const EmailSchema = z.string()
14  .email('Invalid email format')
15  .transform((val) => val.toLowerCase().trim());
16
17const PasswordSchema = z.string()
18  .min(8, 'Password must be at least 8 characters')
19  .regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/, 
20    'Password must contain uppercase, lowercase, number, and special character');
21
22// User registration with validation
23const CreateUserSchema = z.object({
24  email: EmailSchema,
25  password: PasswordSchema,
26  name: SanitizedString.min(2).max(50),
27  bio: SanitizedString.max(500).optional(),
28  website: z.string().url().optional().transform((val) => {
29    // Ensure HTTPS for external links
30    if (val && !val.startsWith('https://')) {
31      return `https://${val.replace(/^https?:\/\//, '')}`;
32    }
33    return val;
34  })
35});
36
37app.post('/users', {
38  body: CreateUserSchema,
39  handler: async ({ body }) => {
40    // All input is automatically validated and sanitized
41    const { email, password, name, bio, website } = body;
42    
43    // Additional security checks
44    if (await isEmailBlacklisted(email)) {
45      throw new Error('Email domain not allowed');
46    }
47    
48    // Hash password
49    const hashedPassword = await bcrypt.hash(password, 12);
50    
51    const user = await createUser({
52      email,
53      password: hashedPassword,
54      name,
55      bio,
56      website
57    });
58    
59    return { id: user.id, email: user.email, name: user.name };
60  }
61});

SQL Injection Prevention

typescript

1// MoroJS automatically uses parameterized queries
2import { db } from '@morojs/moro/database';
3
4// Safe database queries (automatically parameterized)
5app.get('/users/:id', {
6  params: z.object({
7    id: z.string().uuid('Invalid user ID format')
8  }),
9  handler: async ({ params }) => {
10    // This is automatically safe from SQL injection
11    const user = await db.query(
12      'SELECT id, email, name FROM users WHERE id = $1',
13      [params.id]
14    );
15    
16    return user[0] || null;
17  }
18});
19
20// Search with additional validation
21app.get('/users/search', {
22  query: z.object({
23    q: z.string()
24      .min(2, 'Search query too short')
25      .max(100, 'Search query too long')
26      .transform((val) => {
27        // Remove dangerous characters for search
28        return val.replace(/[<>"'%;()&+]/g, '');
29      })
30  }),
31  handler: async ({ query }) => {
32    // Use full-text search with proper escaping
33    const results = await db.query(
34      'SELECT id, name, email FROM users WHERE search_vector @@ plainto_tsquery($1) LIMIT 20',
35      [query.q]
36    );
37    
38    return results;
39  }
40});

Security Monitoring & Logging

Security Event Logging

typescript

1import { securityLogger } from '@morojs/moro/security';
2
3// Security event middleware
4const securityMonitoring = (req, res, next) => {
5  // Log suspicious patterns
6  const suspiciousPatterns = [
7    /\.\.\//, // Directory traversal
8    /<script/i, // XSS attempts
9    /union.*select/i, // SQL injection
10    /eval\s*\(/i, // Code injection
11    /javascript:/i // JavaScript protocol
12  ];
13  
14  const userAgent = req.get('User-Agent') || '';
15  const url = req.url;
16  const body = JSON.stringify(req.body);
17  
18  // Check for suspicious patterns
19  const suspicious = suspiciousPatterns.some(pattern => 
20    pattern.test(url) || pattern.test(body) || pattern.test(userAgent)
21  );
22  
23  if (suspicious) {
24    securityLogger.warn('Suspicious request detected', {
25      ip: req.ip,
26      userAgent,
27      url,
28      method: req.method,
29      body: req.body,
30      headers: req.headers,
31      timestamp: new Date().toISOString(),
32      severity: 'HIGH'
33    });
34    
35    // Optional: Block the request
36    // return res.status(400).json({ error: 'Request blocked' });
37  }
38  
39  // Log failed authentication attempts
40  res.on('finish', () => {
41    if (req.path.includes('/auth/') && res.statusCode === 401) {
42      securityLogger.warn('Failed authentication attempt', {
43        ip: req.ip,
44        userAgent,
45        path: req.path,
46        timestamp: new Date().toISOString()
47      });
48    }
49  });
50  
51  next();
52};
53
54app.use(securityMonitoring);

Real-time Security Alerts

typescript

1import { SecurityMonitor } from '@morojs/moro/security';
2
3const monitor = new SecurityMonitor({
4  // Alert thresholds
5  thresholds: {
6    failedLogins: { count: 5, window: '5m' },
7    suspiciousRequests: { count: 10, window: '1m' },
8    rateLimitExceeded: { count: 3, window: '15m' }
9  },
10  
11  // Alert channels
12  alerts: {
13    email: {
14      enabled: true,
15      recipients: ['security@example.com'],
16      smtp: {
17        host: process.env.SMTP_HOST,
18        auth: {
19          user: process.env.SMTP_USER,
20          pass: process.env.SMTP_PASS
21        }
22      }
23    },
24    slack: {
25      enabled: true,
26      webhook: process.env.SLACK_WEBHOOK_URL,
27      channel: '#security-alerts'
28    },
29    webhook: {
30      enabled: true,
31      url: process.env.SECURITY_WEBHOOK_URL,
32      headers: {
33        'Authorization': `Bearer ${process.env.WEBHOOK_TOKEN}`
34      }
35    }
36  }
37});
38
39// Monitor security events
40monitor.on('failed-login-threshold', (data) => {
41  monitor.alert('HIGH', 'Multiple failed login attempts detected', {
42    ip: data.ip,
43    attempts: data.count,
44    timeWindow: data.window,
45    action: 'Consider blocking IP address'
46  });
47});
48
49monitor.on('suspicious-activity', (data) => {
50  monitor.alert('CRITICAL', 'Potential attack detected', {
51    pattern: data.pattern,
52    ip: data.ip,
53    requests: data.requests,
54    action: 'Immediate investigation required'
55  });
56});

Security Best Practices

Security Checklist

  • Use HTTPS in production
  • Validate and sanitize all inputs
  • Implement proper authentication
  • Use parameterized queries
  • Set security headers
  • Enable rate limiting
  • Monitor security events
  • Keep dependencies updated

Common Vulnerabilities

  • SQL Injection
  • Cross-Site Scripting (XSS)
  • Cross-Site Request Forgery (CSRF)
  • Insecure Direct Object References
  • Security Misconfiguration
  • Broken Authentication
  • Sensitive Data Exposure
  • Insufficient Logging & Monitoring

Security Configuration Checklist

typescript

1// Production security configuration
2const productionSecurityConfig = {
3  // Force HTTPS
4  server: {
5    https: {
6      enabled: true,
7      redirectHttp: true,
8      hsts: {
9        maxAge: 31536000,
10        includeSubDomains: true,
11        preload: true
12      }
13    }
14  },
15  
16  // Security headers
17  helmet: {
18    contentSecurityPolicy: {
19      directives: {
20        defaultSrc: ["'self'"],
21        scriptSrc: ["'self'"],
22        styleSrc: ["'self'", "'unsafe-inline'"],
23        imgSrc: ["'self'", "data:", "https:"],
24        connectSrc: ["'self'"],
25        fontSrc: ["'self'"],
26        objectSrc: ["'none'"],
27        mediaSrc: ["'self'"],
28        frameSrc: ["'none'"]
29      }
30    },
31    frameguard: { action: 'deny' },
32    noSniff: true,
33    xssFilter: true,
34    referrerPolicy: { policy: 'strict-origin-when-cross-origin' }
35  },
36  
37  // Rate limiting
38  rateLimit: {
39    global: { max: 1000, window: '15m' },
40    auth: { max: 5, window: '15m' },
41    api: { max: 100, window: '15m' }
42  },
43  
44  // CORS
45  cors: {
46    origin: ['https://yourdomain.com'],
47    credentials: true,
48    methods: ['GET', 'POST', 'PUT', 'DELETE'],
49    allowedHeaders: ['Content-Type', 'Authorization']
50  },
51  
52  // Authentication
53  auth: {
54    jwt: {
55      secret: process.env.JWT_SECRET, // Use strong secret
56      algorithm: 'HS256',
57      expiresIn: '1h'
58    }
59  },
60  
61  // Logging
62  logging: {
63    level: 'info',
64    security: {
65      enabled: true,
66      logFailedAttempts: true,
67      logSuspiciousActivity: true
68    }
69  }
70};

Next Steps