# FC-Security

A comprehensive security suite for LoopBack 4 applications providing multi-layered protection against various security threats.

## Overview

FC-Security provides modular security features including:

- SQL Injection Protection
- Cross-Site Scripting (XSS) Protection
- Rate Limiting
- CORS Management
- DDoS Protection
- Security Headers
- File Upload Security
- Input Validation
- **Health Check Bypass** - Configurable paths that automatically bypass security checks
- **Field Skipping** - Skip security validation for specific fields (e.g., passwords, API keys)
- **URL Skipping** - Skip all security checks for specific URL patterns

**Note:** Authentication and Authorization are handled by the separate `fc-auth` package.

## Quick Start

### Health Check Configuration (New!)

Configure paths that should bypass security checks (e.g., for AWS ELB health checks):

```typescript
const securityMiddleware = new SecurityMiddleware({
  // Health check paths that bypass all security
  healthCheckPaths: ['/health', '/api/health', '/monitoring/ping'],

  cors: {
    origin: ['*.yourcompany.com', 'null'], // "null" allows no-origin requests
  },
  // ... other security config
});
```

### Field and URL Skipping (New!)

Skip security validation for specific fields or entire URL patterns:

```typescript
const securityMiddleware = new SecurityMiddleware({
  // Skip security checks for sensitive fields that might contain special characters
  skipFields: [
    'password',        // Password fields
    'token',           // Auth tokens  
    'secret',          // API secrets
    'apiKey',          // API keys
    'privateKey'       // Private keys
  ],
  
  // Skip all security checks for specific URL patterns
  skipUrls: [
    '/auth/login',     // Exact URL match
    '/api/public/*',   // Wildcard pattern
    '/upload/*',       // File upload endpoints
    '/webhooks/*'      // Webhook endpoints
  ],

  // ... other security config
});
```

**Use Cases for Field Skipping:**
- **Passwords**: May contain SQL-like patterns or special characters
- **API Keys**: Often contain encoded data that triggers false positives
- **Encrypted Data**: Base64 or hex-encoded content may appear malicious
- **Binary Data**: File uploads or binary content encoded as strings

**Use Cases for URL Skipping:**
- **Authentication Endpoints**: Login/register forms with sensitive data
- **File Upload Endpoints**: Binary data that may trigger security alerts
- **Public APIs**: Endpoints that need to accept any content
- **Webhook Endpoints**: External integrations with unpredictable payloads

### Module Enable/Disable Configuration (New!)

You can now selectively enable or disable security modules by setting `enabled: false` in their configuration:

```typescript
const securityMiddleware = new SecurityMiddleware({
  cors: {
    enabled: false, // Completely disable CORS handling
  },
  validation: {
    enabled: true, // Keep input validation enabled
    strictMode: false,
  },
  headers: {
    enabled: false, // Disable security headers
  },
  sqlInjection: {
    enabled: true, // Keep SQL injection protection
    strictMode: true,
  },
  xss: {
    enabled: false, // Disable XSS protection
  },
  fileUpload: {
    enabled: false, // File upload validation is disabled by default
  },
});
```

**Benefits:**

- **Performance**: Disabled modules are completely bypassed, improving performance
- **Flexibility**: Enable only the security features you need
- **Environment-specific**: Different configurations for dev, staging, and production
- **Backwards Compatible**: All modules are enabled by default (except file upload)

### Error Message Configuration (New!)

Control what error messages are sent to clients when security violations occur:

```typescript
const securityMiddleware = new SecurityMiddleware({
  errorResponse: {
    // Send detailed errors (useful for testing/debugging)
    exposeDetailedErrors: process.env.NODE_ENV === 'development',
    // Custom message when detailed errors are disabled
    customErrorMessage: 'Request blocked by security policy',
  },
  logging: {
    enabled: true,
    logLevel: 'info',
  },
});
```

**Error Response Examples:**

```javascript
// When exposeDetailedErrors: true (development/testing)
{
  "error": "Security Violation",
  "message": "Potential SQL injection detected in query parameter (pattern: UNION SELECT)",
  "timestamp": "2025-08-14T10:30:00.000Z",
  "requestId": "sec_1692012600000_abc123",
  "details": {
    "errorType": "SQL_INJECTION",
    "severity": "HIGH"
  }
}

// When exposeDetailedErrors: false (production)
{
  "error": "Security Violation",
  "message": "Request blocked by security policy",
  "timestamp": "2025-08-14T10:30:00.000Z",
  "requestId": "sec_1692012600000_abc123"
}
```

**Use Cases:**

- **Testing**: Enable detailed errors for end-to-end test validation
- **Development**: Show specific security violations for debugging
- **Production**: Generic messages to avoid information disclosure
- **Custom Messages**: Branded or user-friendly error messages

For detailed documentation, see [HEALTH_CHECK_CONFIGURATION.md](./HEALTH_CHECK_CONFIGURATION.md) and [SECURITY_README.md](./SECURITY_README.md).

## Basic Usage

### TimerProvider

TimerProvider is automatically bound to your Application's
[Context](http://loopback.io/doc/en/lb4/Context.html) using the LogComponent
which exports this provider with a binding key of `extension-starter.timer`. You
can learn more about components in the
[related resources section](#related-resources).

This provider makes available to your application a timer function which given a
start time _(given as an array [seconds, nanoseconds])_ can give you a total
time elapsed since the start in milliseconds. The timer can also start timing if
no start time is given. This is used by LogComponent to allow a user to time a
Sequence.

_NOTE:_ _You can get the start time in the required format by using
`this.logger.startTimer()`._

You can provide your own implementation of the elapsed time function by binding
it to the binding key (accessible via `ExtensionStarterBindings`) as follows:

```ts
app.bind(ExtensionStarterBindings.TIMER).to(timerFn);
```

### LogProvider

LogProvider can automatically be bound to your Application's Context using the
LogComponent which exports the provider with a binding key of
`extension-starter.actions.log`.

The key can be accessed by importing `ExtensionStarterBindings` as follows:

**Example: Binding Keys**

```ts
import {ExtensionStarterBindings} from 'HelloExtensions';
// Key can be accessed as follows now
const key = ExtensionStarterBindings.LOG_ACTION;
```

LogProvider gives us a sequence action and a `startTimer` function. In order to
use the sequence action, you must define your own sequence as shown below.

**Example: Sequence**

```ts
class LogSequence implements SequenceHandler {
  constructor(
    @inject(coreSequenceActions.FIND_ROUTE) protected findRoute: FindRoute,
    @inject(coreSequenceActions.PARSE_PARAMS)
    protected parseParams: ParseParams,
    @inject(coreSequenceActions.INVOKE_METHOD) protected invoke: InvokeMethod,
    @inject(coreSequenceActions.SEND) protected send: Send,
    @inject(coreSequenceActions.REJECT) protected reject: Reject,
    // We get the logger injected by the LogProvider here
    @inject(ExtensionStarterBindings.LOG_ACTION) protected logger: LogFn,
  ) {}

  async handle(context: RequestContext) {
    const {request, response} = context;

    // We define these variable outside so they can be accessed by logger.
    let args: any = [];
    let result: any;

    // Optionally start timing the sequence using the timer
    // function available via LogFn
    const start = this.logger.startTimer();

    try {
      const route = this.findRoute(request);
      args = await this.parseParams(request, route);
      result = await this.invoke(route, args);
      this.send(response, result);
    } catch (error) {
      result = error; // so we can log the error message in the logger
      this.reject(context, error);
    }

    // We call the logger function given to us by LogProvider
    this.logger(request, args, result, start);
  }
}
```

Once a sequence has been written, we can just use that in our Application as
follows:

**Example: Application**

```ts
const app = new Application({
  sequence: LogSequence,
});
app.component(LogComponent);

// Now all requests handled by our sequence will be logged.
```

## Related Resources

You can check out the following resource to learn more about providers,
components, sequences, and binding keys.

- [Providers](http://loopback.io/doc/en/lb4/Creating-components.html#providers)
- [Creating Components](http://loopback.io/doc/en/lb4/Creating-components.html)
- [Using Components](http://loopback.io/doc/en/lb4/Components.html)
- [Sequence](http://loopback.io/doc/en/lb4/Sequence.html)
- [Binding Keys](http://loopback.io/doc/en/lb4/Decorators.html)
