Dns Rebinding in Feathersjs with Jwt Tokens
Dns Rebinding in Feathersjs with Jwt Tokens — how this specific combination creates or exposes the vulnerability
DNS Rebinding is a client-side network attack where an attacker forces a victim’s browser to resolve a domain to an arbitrary IP address, often an internal host. When this occurs in a FeathersJS application that relies on JWT tokens for authentication, the threat surface changes in a way that can bypass same-origin protections and token handling assumptions.
FeathersJS is a framework that typically uses token-based authentication with JWT, where access tokens are validated on each request. If an application exposes endpoints to unauthenticated or weakly authenticated clients (for example, to support real-time connections or public services), DNS Rebinding can be used to make a victim’s browser send requests to the FeathersJS server while the browser holds a valid JWT. Because the browser automatically includes cookies and authorization headers for the target domain, a rebound request may carry the JWT even when the attacker’s page cannot directly read it.
The specific risk arises when FeathersJS services accept requests on shared hostnames or when a single server serves both public and authenticated APIs on different paths. An attacker can register a domain, resolve it to the FeathersJS server’s internal IP after the initial visit, and then issue crafted requests that trigger endpoints expecting a valid JWT. If the server does not strictly validate the origin and relies only on token presence, the request may be processed with elevated privileges. This can lead to unauthorized data access or unsafe operations, especially if CORS rules are permissive or if the application exposes routes intended for internal consumption.
Additionally, if the FeathersJS server performs service discovery or dynamic client configuration based on hostname information, DNS Rebinding can supply maliciously controlled DNS records to influence how the server treats JWT validation or scope interpretation. Even though JWT tokens themselves are cryptographically signed, the server must still verify that the token is intended for the expected audience and issued for the correct resource. A rebinding scenario can exploit loose hostname checks to make a token appear valid in a context it was not designed for.
To illustrate a secure FeathersJS setup that explicitly handles JWT validation, consider a service that verifies tokens against expected issuer and audience claims. The following example shows a FeathersJS hook that enforces strict JWT checks on protected endpoints, reducing the risk of token misuse via DNS Rebinding:
const jwt = require('@feathersjs/authentication-jwt');
const { iff, isProvider } = require('feathers-hooks-common');
module.exports = {
before: {
all: [
jwt.authenticate(),
iff(
isProvider('external'),
context => {
const { app, params } = context;
const { token } = params;
if (!token || !token.__jwt) {
throw new Error('Not authenticated');
}
// Enforce expected issuer and audience
if (token.iss !== 'https://api.yourcompany.com' || token.aud !== 'feathers-api') {
throw new Error('Invalid token claims');
}
return context;
}
)
]
}
};
Jwt Tokens-Specific Remediation in Feathersjs — concrete code fixes
Remediation for DNS Rebinding when using JWT tokens in FeathersJS focuses on strict validation of token metadata, tightening endpoint exposure, and ensuring that requests are evaluated in the correct network context. The goal is to prevent a token accepted for one origin from being usable in a different network context induced by rebinding.
First, enforce strict issuer and audience validation in your JWT strategy configuration. This ensures that tokens are only accepted if they explicitly match your service’s identity, making it harder for a rebounded request to appear legitimate.
// src/authentication.js
const { AuthenticationService, JWTStrategy } = require('@feathersjs/authentication-jwt');
module.exports = {
service: 'authentication',
entity: 'user',
jwt: {
secret: process.env.JWT_SECRET,
algorithms: ['HS256'],
issuer: 'https://api.yourcompany.com',
audience: 'feathers-api'
}
};
Second, add a hook that verifies the request’s Host header and referer when applicable, rejecting requests that do not match expected hostnames. This complements JWT validation by adding a network-layer check that can detect suspicious rebinding attempts.
// src/hooks/verify-host.js
module.exports = function verifyHost(expectedHost) {
return context => {
const { headers } = context.params;
const host = headers && headers.host ? headers.host.split(':')[0] : '';
if (host !== expectedHost) {
throw new Error('Host validation failed');
}
return context;
};
};
// In your service configuration
const { iff, isProvider } = require('feathers-hooks-common');
module.exports = {
before: {
all: [
verifyHost('api.yourcompany.com'),
iff(isProvider('external'), require('./hooks/verify-jwt-claims'))
]
}
};
Third, avoid binding authenticated endpoints to shared or wildcard hostnames that could be manipulated via DNS. Configure your HTTP server to listen only on expected interfaces and use explicit route guards in FeathersJS to ensure that sensitive operations require re-authentication or additional checks.
// src/hooks/require-reauth.js
module.exports = function requireReauth(context) {
const { user, params } = context;
if (!user || !params.accessTokenSchemedCheck) {
throw new Error('Reauthentication required for sensitive action');
}
return context;
};
Finally, monitor and log authentication anomalies. If your FeathersJS app uses the dashboard or CLI to track scans, correlate findings with authentication events to detect patterns that may indicate abuse. While middleBrick can highlight unusual API behavior, these code-level controls reduce the likelihood that a JWT issued for one context is misused across a rebound connection.