Dns Rebinding in Koa with Bearer Tokens
Dns Rebinding in Koa with Bearer Tokens — how this specific combination creates or exposes the vulnerability
DNS rebinding is a client-side attack that manipulates DNS responses to make a browser believe a remote host is reachable at an attacker-controlled IP after the initial page load. When this technique targets a Koa application that relies on Bearer Tokens for authorization, the combination can bypass same-origin protections and expose privileged endpoints.
In a typical setup, a Koa server uses a middleware pattern to validate Authorization headers containing Bearer Tokens. If an endpoint performs privileged actions based solely on a valid token and does not enforce additional origin checks, an attacker can serve a page that resolves a benign hostname (e.g., api-internal.example.com) to an internal IP such as 127.0.0.1 after the page has loaded. The victim’s browser then makes requests to this hostname with the Bearer Token included automatically, because the token is stored in an Authorization header or a secure cookie used by the client-side code. Since the token is valid, the Koa route processes the request as if it originated from the expected domain, even though the source IP or context has changed.
The risk is amplified when Koa routes assume that requests with a valid Bearer Token are inherently safe from network-based address manipulation. For example, an endpoint like /admin/reset might check for a Bearer Token in the header but not validate the request’s origin or enforce strict referrer checks. During a rebinding sequence, the attacker’s page can trigger cross-origin requests to this endpoint, and the browser will include the Bearer Token if it is stored in an Authorization header that JavaScript can set or in a cookie without SameSite=Strict protections. Because the token is presented, the server-side logic in Koa grants access, effectively bypassing network-level segregation between internal services and external clients.
OpenAPI specifications analyzed by middleBrick often expose such design gaps when endpoint definitions do not explicitly bind authorization to network context or when security schemes lack host validation requirements. The scanner’s checks for BOLA/IDOR and Property Authorization can highlight routes where token validation occurs without proper origin or referer verification, which is a precursor to rebinding-related abuse. Even though middleBrick does not fix these issues, its findings can guide developers to apply complementary controls in Koa, such as validating the Origin header and binding token usage to expected client contexts.
Bearer Tokens-Specific Remediation in Koa — concrete code fixes
To mitigate DNS rebinding risks when using Bearer Tokens in Koa, you should enforce origin validation, tighten token scope, and avoid relying on token-only checks. Below are concrete code examples that demonstrate secure patterns.
1. Validate Origin and Referer Headers
Before processing a request with a Bearer Token, verify that the request originates from an expected source. This reduces the impact of DNS rebinding by ensuring that even if the token is presented, the request’s origin is authorized.
const Koa = require('koa');
const app = new Koa();
const allowedOrigins = ['https://app.example.com', 'https://api.example.com'];
app.use(async (ctx, next) => {
const origin = ctx.request.header.origin;
const referer = ctx.request.header.referer;
const token = ctx.request.header.authorization && ctx.request.header.authorization.startsWith('Bearer ')
? ctx.request.header.authorization.slice(7)
: null;
if (!token) {
ctx.status = 401;
ctx.body = { error: 'Unauthorized' };
return;
}
if (!origin || !allowedOrigins.includes(origin)) {
ctx.status = 403;
ctx.body = { error: 'Forbidden origin' };
return;
}
// Optional: validate referer for additional assurance
if (referer && !allowedOrigins.some(o => referer.startsWith(o))) {
ctx.status = 403;
ctx.body = { error: 'Forbidden referer' };
return;
}
// Attach user info after token verification (pseudo)
ctx.state.user = verifyToken(token); // implement your token verification
await next();
});
app.use(async (ctx) => {
ctx.body = { message: 'Access granted' };
});
app.listen(3000);
2. Use SameSite Cookies and Secure Storage for Token Handling
If you store Bearer Tokens in cookies rather than JavaScript-accessible headers, configure SameSite=Strict and Secure flags to prevent browsers from sending them in cross-origin requests triggered by DNS rebinding.
const cookie = require('cookie');
// Set cookie with protections
ctx.set('Set-Cookie', cookie.serialize('token', 'your-secure-token', {
httpOnly: true,
secure: true,
sameSite: 'strict',
path: '/',
}));
// Middleware to read and validate cookie token
app.use(async (ctx, next) => {
const cookies = cookie.parse(ctx.request.header.cookie || '');
const token = cookies.token;
if (!token || !isValid(token)) {
ctx.status = 401;
ctx.body = { error: 'Unauthorized' };
return;
}
ctx.state.user = verifyToken(token);
await next();
});
3. Scope Tokens to Specific Hosts or Paths
Issue tokens that are bound to particular hostnames or API paths. During validation, confirm that the request target matches the token’s intended scope. This approach ensures that even if a token is leaked via a rebinding attack, it cannot be reused against critical internal endpoints.
function verifyToken(token) {
// Decode JWT or validate against a store; check 'aud' and 'scope'
const payload = decodeJwt(token);
if (!payload || payload.aud !== 'api.example.com' || !payload.scope.includes('admin:write')) {
throw new Error('Invalid token scope');
}
return payload;
}