Logging Monitoring Failures in Feathersjs with Hmac Signatures
Logging Monitoring Failures in Feathersjs with Hmac Signatures — how this specific combination creates or exposes the vulnerability
FeathersJS applications that use HMAC signatures for request authentication can still suffer from critical logging and monitoring failures when signature validation logic is incomplete or when observability practices do not capture security-relevant events. A common pattern is to verify the signature but omit structured audit logs for failed validations, success events, or anomalous request rates. Without explicit logging of signature verification outcomes, timestamps, and principal identifiers, operators lose visibility into tampered or replayed requests.
Consider an endpoint protected by an HMAC scheme where the client sends X-Client-Id, X-Timestamp, and X-Signature. If the service does not log failed signature checks with sufficient context (client ID, timestamp skew, request path), an attacker can probe with modified payloads and the defense remains invisible. A monitoring gap emerges because metrics and alerting dashboards do not track signature failure rates or spikes in verification exceptions. This enables subtle abuse such as replay attacks or incremental tampering to go unnoticed until data integrity is compromised.
Another scenario involves logging sensitive material inadvertently. If the implementation logs the full shared secret or concatenates secret material with request data before hashing, observability outputs become a secret store. An attacker who gains access to logs can recover keys and forge signatures. Logging should therefore capture only non-sensitive metadata: signature validity result, request identifier, client ID, timestamp, and outcome. Correlation IDs that tie runtime exceptions to signature verification steps help investigations but must avoid including raw signature inputs or secrets.
FeathersJS middleware that does not integrate with application monitoring or structured log sinks increases mean time to detect (MTTD). Without exporting verification metrics to time-series stores or alerting on thresholds (for example, a high rate of invalid signatures), teams lack early detection. Structured logs should include fields used by security tooling to detect patterns such as credential stuffing, timestamp replays, and geographic anomalies. Runtime observability must therefore treat HMAC validation as a first-class security signal, emitting consistent, parsable events for every verification cycle.
Hmac Signatures-Specific Remediation in Feathersjs — concrete code fixes
Remediation centers on strict signature verification, safe logging, and instrumenting observable signals. Below is a complete, syntactically correct FeathersJS service mixin that validates HMAC-SHA256 signatures, avoids logging secrets, and emits structured audit events.
// src/middleware/hmac-validation.mjs
import crypto from 'crypto';
const HMAC_ALGO = 'sha256';
const SIGNATURE_HEADER = 'X-Signature';
const TIMESTAMP_HEADER = 'X-Timestamp';
const CLIENT_ID_HEADER = 'X-Client-Id';
const ACCEPTABLE_SKEW_MS = 30000; // 30 seconds
function getSigningKey(clientId) {
// Retrieve key from a secure store; never log this value
const keyStore = {
'alpha-client': process.env.HMAC_KEY_ALPHA,
'beta-client': process.env.HMAC_KEY_BETA,
};
return keyStore[clientId] || null;
}
function buildExpectedSignature(secret, timestamp, method, url, body) {
const payload = `${timestamp}|${method.toUpperCase()}|${url}|${body}`;
return crypto.createHmac(HMAC_ALGO, secret).update(payload).digest('hex');
}
export default function hmacValidation() {
return async context => {
const { params } = context;
const headers = params.headers || {};
const clientId = headers[CLIENT_ID_HEADER];
const timestamp = headers[TIMESTAMP_HEADER];
const receivedSignature = headers[SIGNATURE_HEADER];
const method = params.type || 'POST';
const url = params.path || '';
const body = JSON.stringify(params.data || {});
if (!clientId || !timestamp || !receivedSignature) {
// Structured audit log for monitoring pipelines
context.app.log('hmac:validation:fail', {
reason: 'missing_headers',
clientId,
path: url,
timestamp,
});
throw new Error('Missing authentication headers');
}
const key = getSigningKey(clientId);
if (!key) {
context.app.log('hmac:validation:fail', {
reason: 'unknown_client',
clientId,
path: url,
timestamp,
});
throw new Error('Invalid client');
}
const now = Date.now();
const tsMs = Number(timestamp);
if (Number.isNaN(tsMs) || Math.abs(now - tsMs) > ACCEPTABLE_SKEW_MS) {
context.app.log('hmac:validation:fail', {
reason: 'timestamp_skew',
clientId,
path: url,
timestamp: tsMs,
skewMs: now - tsMs,
});
throw new Error('Timestamp skew detected');
}
const expected = buildExpectedSignature(key, timestamp, method, url, body);
const valid = crypto.timingSafeEqual(
Buffer.from(expected, 'hex'),
Buffer.from(receivedSignature, 'hex')
);
if (!valid) {
context.app.log('hmac:validation:fail', {
reason: 'invalid_signature',
clientId,
path: url,
timestamp: tsMs,
});
throw new Error('Invalid signature');
}
// Success audit event for monitoring
context.app.log('hmac:validation:success', {
reason: 'verified',
clientId,
path: url,
timestamp: tsMs,
});
// Proceed safely; do not log signature or secret
return context;
};
}
In your service definition, apply the mixin and ensure structured logs are forwarded to an observability platform that supports alerting on event rates:
// src/services/orders/orders.class.js
import { Service as createService } from 'feathersjs';
import hmacValidation from '../middleware/hmac-validation.mjs';
class Orders {
constructor(options) {
this.name = 'orders';
this.options = options || {};
}
setup(app) {
this.app = app;
this.log = app.get('logger').child({ service: this.name });
}
find(params) {
// Example business logic
return Promise.resolve({
total: 1,
data: [{ id: 'a1b2', item: 'widget' }],
});
}
}
export default function setupOrders(options) {
const app = options.app;
const service = new Orders(options);
app.use('/orders', createService({
name: 'orders',
async middleware: {
before: [hmacValidation()],
after: [],
error: [],
},
}));
app.service('orders').on('created', event => {
app.log('orders:created', {
orderId: event.id,
clientId: event.params.headers['X-Client-Id'],
timestamp: Date.now(),
});
});
}
Key remediation practices:
- Log outcomes, not secrets: emit structured events with client ID, path, timestamp, and verification result; never log shared secrets or raw signatures.
- Use
crypto.timingSafeEqualto prevent timing attacks during signature comparison. - Validate timestamp freshness to mitigate replay attacks; log skew metrics for monitoring anomaly detection.
- Instrument success and failure events with correlation-friendly fields so monitoring tools can trigger alerts on abnormal signature failure rates.