Dictionary Attack in Feathersjs with Jwt Tokens
Dictionary Attack in Feathersjs with Jwt Tokens — how this specific combination creates or exposes the vulnerability
A dictionary attack against a FeathersJS service that uses JWT tokens typically targets the authentication endpoint or a password-reset flow. FeathersJS itself does not introduce a bug; the risk arises when an application exposes a login route that accepts arbitrary usernames or identifiers and returns a JWT token without enforcing adequate rate limits or account lockout mechanisms.
In Feathers, authentication is commonly configured with an authentication.js file that hooks into services such as users. If an attacker can send many guesses to the POST /authentication route with different usernames or passwords, they may discover valid accounts and obtain a signed JWT for each successful guess. Because JWTs represent authenticated identity, possession of a token often grants access to protected services until expiration or revocation.
Another relevant scenario involves token enumeration or timing differences. If a Feathers application reveals whether a username exists during login (for example, by returning different status codes or messages), an attacker can iteratively probe valid accounts and then focus dictionary efforts on those accounts. Even when JWTs are used, weak password policies or reused credentials increase the likelihood that a guessed password matches a valid account and yields a usable token.
Additionally, if the application issues JWTs with insufficient entropy in the token ID (jti) or predictable payloads, attackers might infer token patterns or replay tokens across accounts. Misconfigured CORS or missing CSRF protections can also enable browser-based dictionary attempts via crafted requests, especially when tokens are stored in local storage and transmitted automatically by the client.
Feathers services often expose metadata in error messages that aid attackers. For example, distinguishing between incorrect password and user not found gives attackers an oracle to map valid usernames. Combined with a predictable authentication route and permissive rate limiting, this creates conditions where a dictionary attack can systematically harvest valid JWTs for later misuse.
Jwt Tokens-Specific Remediation in Feathersjs — concrete code fixes
To reduce the risk of dictionary attacks while using JWT tokens in FeathersJS, apply a combination of rate control, uniform responses, strong token handling, and secure authentication configuration.
Rate limiting and account protection
Implement rate limiting at the application or service level so that authentication endpoints reject excessive requests from a single IP or identifier. Use a sliding window or token-bucket approach to smooth bursts without unduly impacting legitimate users.
// Example: feathers-rate-limit configuration (conceptual)
const rateLimit = require('feathers-rate-limit');
app.configure(rateLimit({
store: new Map(), // or Redis store in production
duration: 15 * 60 * 1000, // 15 minutes
max: 10 // max 10 attempts per identifier
}));
app.use('/authentication', app.authentication.hooks.rateLimit);
Uniform authentication responses
Ensure that login responses do not reveal whether a username exists. Return a consistent response shape and HTTP status code for both invalid credentials and unknown users. This denies attackers an oracle for account enumeration.
// Example: Custom authentication hook to normalize responses
const { AuthenticationError } = require('@feathersjs/errors');
app.service('authentication').hooks({
before: {
async create(hook) {
const { email, password } = hook.data;
const user = await hook.app.service('users').find({ query: { email } });
if (!user.data.length) {
// Always throw a generic error
throw new AuthenticationError('Invalid credentials');
}
// Continue with hook.app.service('authentication').create(hook.data) if needed
}
}
});
Secure JWT payload and handling
When issuing JWTs, include a random jti and avoid embedding sensitive data. Configure token lifetimes conservatively and enforce HTTPS. Validate tokens on each request and reject unsigned or malformed tokens.
// Example: Feathers authentication configuration with JWT
const authentication = require('@feathersjs/authentication');
const jwt = require('@feathersjs/authentication-jwt');
app.configure(authentication({
secret: process.env.AUTH_SECRET,
strategies: ['jwt'],
path: '/authentication'
}));
app.configure(jwt({
header: { typ: 'JWT', alg: 'HS256' },
tokenOptions: {
expiresIn: '15m',
jwtid: () => require('crypto').randomUUID()
}
}));
Additional hardening
- Enforce strong password policies and consider multi-factor authentication for sensitive endpoints.
- Use secure, HttpOnly cookies for token storage when possible, and set appropriate SameSite and CORS settings.
- Monitor authentication logs for high failure rates and automate alerts for suspicious patterns.