HIGH dictionary attackfeathersjshmac signatures

Dictionary Attack in Feathersjs with Hmac Signatures

Dictionary Attack in Feathersjs with Hmac Signatures — how this specific combination creates or exposes the vulnerability

A dictionary attack against a FeathersJS service that uses Hmac Signatures typically targets the authentication route where a client computes an Hmac over a payload (often including a username or email) and sends it alongside the raw identifier. If the server processes these requests in a way that produces different responses or timing behavior depending on whether the provided identifier exists, the attacker can learn valid user identifiers without needing a password. FeathersJS does not prescribe a particular Hmac implementation, so developers often implement the signature verification in before hooks or a custom authentication service. When the lookup of the user by email or username occurs before Hmac verification, or when error messages differ between missing user and invalid signature, the endpoint becomes susceptible to online dictionary attacks.

For example, an attacker enumerates likely usernames or email addresses and crafts requests with an Hmac computed over a static payload using a guessed identity. If the server returns a distinct error such as “user not found” versus “invalid signature”, the attacker can infer whether the identity exists. Even when the server attempts to mitigate this by performing a constant-time comparison after user lookup, the prior database query can leak information through timing channels or rate-limiting differences. In FeathersJS, if the authentication service queries the database eagerly and then proceeds to verify the Hmac, the presence or absence of a record can be inferred via response times or error codes, enabling an attacker to build a list of valid accounts.

Another vector arises when the Hmac covers a subset of the request but the server accepts requests with missing or malformed identifiers. An attacker can submit dictionary guesses for the user identifier while keeping the Hmac valid for a static payload, observing whether the request is rejected before or after authorization logic. This can expose whether a given identifier is authorized to access a particular resource, especially if combined with unauthenticated endpoints that list services or integrations. The issue is not the Hmac algorithm itself, but the surrounding application logic in FeathersJS that ties signature validation to identifier lookup, error handling, and rate-limiting behavior.

Hmac Signatures-Specific Remediation in Feathersjs — concrete code fixes

To reduce the risk of dictionary attacks, ensure that user existence checks and Hmac verification are performed in a way that does not leak information through timing or error messages. Use a constant-time comparison for signatures and avoid branching logic based on whether a user exists before the signature is validated. In FeathersJS, you can centralize authentication logic in a custom authentication hook that first computes the expected Hmac over normalized payload data and then performs a single, constant-time user lookup only after signature validation succeeds.

Below is a realistic example using the Node.js crypto module in a FeathersJS before hook. The hook extracts the identifier and Hmac from the request, computes the Hmac over a canonical JSON string, and compares it using crypto.timingSafeEqual. Only after a valid signature is confirmed does it fetch the user, ensuring that timing differences do not reveal whether the user exists.

const crypto = require('node:crypto');

// Assume app is your FeathersJS instance and a secret is shared between client and server
const SHARED_SECRET = process.env.HMAC_SECRET;

function verifyHmac(payload) {
  const hmac = crypto.createHmac('sha256', SHARED_SECRET);
  // Use a canonical stringification to avoid object ordering issues
  const data = JSON.stringify({ email: payload.email, timestamp: payload.timestamp });
  hmac.update(data);
  return hmac.digest('hex');
}

app.hooks({
  before: {
    create: [context => {
      const { email, signature, timestamp } = context.data;
      if (!email || !signature || !timestamp) {
        throw new Error('Missing authentication fields');
      }
      // Reject requests with stale timestamps to mitigate replay
      const now = Date.now();
      if (Math.abs(now - Number(timestamp)) > 30000) {
        throw new Error('Request expired');
      }
      const expected = verifyHmac({ email, timestamp });
      // Use timing-safe comparison
      const provided = Buffer.from(signature, 'hex');
      const expectedBuf = Buffer.from(expected, 'hex');
      if (provided.length !== expectedBuf.length || !crypto.timingSafeEqual(provided, expectedBuf)) {
        throw new Error('Invalid signature');
      }
      // Only after signature verification, fetch user
      return app.service('users').find({ query: { email } });
    })
  ]
});

On the client side, ensure that the Hmac is computed over the same canonical representation and that the request includes a timestamp to prevent replay attacks. Below is an example of a client computing the signature before invoking a FeathersJS service.

const crypto = require('node:crypto');

function buildSignedRequest(email, secret) {
  const timestamp = Date.now().toString();
  const payload = { email, timestamp };
  const data = JSON.stringify({ email: payload.email, timestamp: payload.timestamp });
  const hmac = crypto.createHmac('sha256', secret);
  hmac.update(data);
  return {
    email,
    timestamp,
    signature: hmac.digest('hex')
  };
}

// Usage: send the returned object as the request body
const signed = buildSignedRequest('[email protected]', process.env.HMAC_SECRET);
// e.g., await app.service('auth').create(signed);

Additional remediation includes applying consistent rate limiting to authentication endpoints and ensuring error responses are uniform regardless of user existence. Configure the FeathersJS error handler to return generic messages for authentication failures and avoid exposing stack traces. These measures help align the behavior with security best practices and reduce the attack surface for dictionary-based enumeration.

Frequently Asked Questions

How can I test that my Hmac implementation in FeathersJS does not leak user existence?
Send requests with valid Hmac signatures for both existing and non-existing user identifiers while keeping other parameters constant; compare response times and error messages. They should be indistinguishable. You can also use a timing-safe comparison in your hook and ensure user lookup occurs only after signature verification.
Does using middleBrick help detect dictionary attack risks in FeathersJS Hmac flows?
middleBrick scans unauthenticated attack surfaces and can identify inconsistencies in error handling, timing differences, and exposed identifiers that may facilitate dictionary attacks. It provides findings and remediation guidance mapped to frameworks such as OWASP API Top 10.