fc-security
v2.4.5
Published
fc security
Readme
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):
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:
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:
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:
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:
// 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 and SECURITY_README.md.
Basic Usage
TimerProvider
TimerProvider is automatically bound to your Application's
Context 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.
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:
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
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
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
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.
