Missing Tls in Feathersjs with Hmac Signatures
Missing Tls in Feathersjs with Hmac Signatures — how this specific combination creates or exposes the vulnerability
FeathersJS is a framework for real-time web applications that commonly exposes services over HTTP and WebSocket. When Hmac Signatures are used for service authentication and integrity, transport security is critical. Without TLS, the secret key used to generate and verify Hmac signatures can be intercepted in transit, and the signed payloads themselves can be observed and replayed.
In a typical FeathersJS setup with Hmac Signatures, the client includes an authorization header derived from a shared secret, a timestamp, and the request payload. If the endpoint is served over HTTP (missing TLS), an on-path attacker can capture the header, extract the timestamp and signature, and replay the request to perform unauthorized actions or escalate privileges. This scenario is common in misconfigured or locally deployed services that omit HTTPS enforcement.
Additionally, service discovery and client registration may transmit the Hmac shared secret or key identifiers without encryption, effectively exposing long-lived credentials. Even if the service validates signatures correctly, the absence of TLS means confidentiality and integrity of the negotiation phase are not guaranteed. Attack patterns such as eavesdropping, session hijacking, and man-in-the-middle (MITM) become feasible, violating authentication and transport integrity controls found in the OWASP API Top 10 and related standards.
Hmac Signatures-Specific Remediation in Feathersjs — concrete code fixes
Remediation focuses on enforcing transport layer security and tightening how Hmac Signatures are generated and validated in FeathersJS. Always serve FeathersJS applications over HTTPS using a properly configured TLS certificate. For local development, use tools like mkcert to create trusted local CAs and avoid disabling TLS.
Below are concrete code examples that show how to implement Hmac Signatures securely in FeathersJS with HTTPS enforced.
Secure FeathersJS Server with Hmac Signature and HTTPS
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const https = require('https');
const fs = require('fs');
const crypto = require('crypto');
const app = express(feathers());
// Load TLS certificates (use a trusted CA in production)
const tlsOptions = {
key: fs.readFileSync('/path/to/private.key'),
cert: fs.readFileSync('/path/to/certificate.crt')
};
// Hmac signature verification hook
function verifyHmac(secret) {
return (context) => {
const { headers, method, url, body } = context.params;
const receivedSignature = headers['x-hmac-signature'];
const receivedTimestamp = headers['x-timestamp'];
if (!receivedSignature || !receivedTimestamp) {
throw new Error('Missing Hmac headers');
}
// Basic replay protection: reject if timestamp is older than 5 minutes
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - parseInt(receivedTimestamp, 10)) > 300) {
throw new Error('Request expired');
}
const payload = typeof body === 'string' ? body : JSON.stringify(body);
const data = `${method.toUpperCase()}\n${url}\n${receivedTimestamp}\n${payload}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(data)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expectedSignature), Buffer.from(receivedSignature))) {
throw new Error('Invalid Hmac signature');
}
return context;
};
}
// Configure a secure service with Hmac verification
app.use('/messages', {
async create(data, params) {
// Business logic here
return { text: data.text, timestamp: Date.now() };
}
}, {
before: {
create: [verifyHmac('your-256-bit-secret-shared-securely')]
}
});
// Start server with HTTPS
https.createServer(tlsOptions, app).listen(443, () => {
console.log('FeathersJS Hmac service running over HTTPS on port 443');
});
Secure FeathersJS Client with Hmac Signature and HTTPS
const axios = require('axios');
const crypto = require('crypto');
const secret = 'your-256-bit-secret-shared-securely';
const apiUrl = 'https://your-feathers-server.example/messages';
function signRequest(method, url, timestamp, body) {
const data = `${method.toUpperCase()}\n${url}\n${timestamp}\n${body}`;
return crypto
.createHmac('sha256', secret)
.update(data)
.digest('hex');
}
async function createMessage(text) {
const timestamp = Math.floor(Date.now() / 1000).toString();
const body = JSON.stringify({ text });
const signature = signRequest('POST', '/messages', timestamp, body);
const response = await axios.post(apiUrl, body, {
headers: {
'Content-Type': 'application/json',
'X-Timestamp': timestamp,
'X-Hmac-Signature': signature
},
httpsAgent: new (require('https').Agent)({ rejectUnauthorized: true })
});
return response.data;
}
createMessage('Hello over secure Hmac channel').then(console.log).catch(console.error);
These examples enforce HTTPS for transport and show how to generate and verify Hmac signatures with timestamp-based replay protection. They map to OWASP API Security Top 10 controls around authentication and integrity, and findings from middleBrick scans will surface missing TLS alongside weak Hmac usage for prioritized remediation.
Related CWEs: encryption
| CWE ID | Name | Severity |
|---|---|---|
| CWE-319 | Cleartext Transmission of Sensitive Information | HIGH |
| CWE-295 | Improper Certificate Validation | HIGH |
| CWE-326 | Inadequate Encryption Strength | HIGH |
| CWE-327 | Use of a Broken or Risky Cryptographic Algorithm | HIGH |
| CWE-328 | Use of Weak Hash | HIGH |
| CWE-330 | Use of Insufficiently Random Values | HIGH |
| CWE-338 | Use of Cryptographically Weak PRNG | MEDIUM |
| CWE-693 | Protection Mechanism Failure | MEDIUM |
| CWE-757 | Selection of Less-Secure Algorithm During Negotiation | HIGH |
| CWE-261 | Weak Encoding for Password | HIGH |