HIGH man in the middlefeathersjs

Man In The Middle in Feathersjs

How Man In The Middle Manifests in Feathersjs

FeathersJS, built on Express and Socket.io, creates real-time APIs that are particularly susceptible to Man-in-the-Middle (MITM) attacks when encryption is misconfigured. The vulnerability typically manifests in two Feathers-specific code paths:

  • Socket.io Transport Fallback: Feathers uses Socket.io for real-time communication. By default, Socket.io attempts multiple transports (WebSocket, HTTP long-polling). If a server does not explicitly enforce secure WebSocket (wss://), an attacker on the network can force a fallback to unencrypted HTTP long-polling. The initial Socket.io handshake and all subsequent polling requests transmit authentication tokens (often in query strings or cookies) and service method payloads in plaintext. For example, a Feathers authentication service call over http://api.example.com exposes JWT tokens or session cookies to interception.
  • Feathers Service Calls Over HTTP: Feathers services are exposed via REST (/api/messages) and real-time events. If the Express server (which Feathers wraps) is not configured to redirect HTTP to HTTPS, REST calls and the initial Socket.io upgrade request travel unencrypted. An attacker can modify request parameters (e.g., id in a GET /api/users/123 call) or inject malicious data into service hooks, leading to BOLA/IDOR or data corruption. Real-world patterns include intercepting a feathersClient.service('users').remove(id) call to change the id and delete unauthorized resources.

A concrete attack scenario: an attacker on a public Wi-Fi network uses a tool like mitmproxy to capture a Feathers client's Socket.io connection attempt. If the server allows polling transport, the attacker forces that transport, then steals the session cookie from the GET /socket.io/?EIO=3&transport=polling... request. With the cookie, they hijack the real-time session and subscribe to private channels like private-chat-456.

Feathersjs-Specific Detection

Detecting MITM vulnerabilities in a FeathersJS API requires checking both the HTTP layer and the Socket.io configuration. Manually, you would:

  • Test if https:// is enforced by visiting http://your-api.com and observing a 301/302 redirect to HTTPS.
  • Inspect the Socket.io connection in browser DevTools: the Network tab should show only wss:// (WebSocket Secure) frames, not ws:// or polling requests. Any transport=polling requests over HTTP indicate a fallback risk.
  • Review the Feathers server's Socket.io configuration. If the transports array includes 'polling' or lacks explicit secure: true in cookie settings, the endpoint is vulnerable.

Automated detection with middleBrick simplifies this. When you scan a FeathersJS API URL (e.g., https://api.feathersapp.com), middleBrick's Encryption check performs:

  • TLS/SSL configuration analysis (certificate validity, protocol support, cipher strength).
  • Active probing of both REST endpoints and the Socket.io handshake endpoint (/socket.io/) to verify that secure transports are enforced and that unencrypted fallbacks are rejected.
  • Correlation with your OpenAPI/Swagger spec (if provided) to see if the schemes field includes https and wss.

For example, a scan might return a high-severity finding: "Socket.io endpoint accepts insecure polling transport over HTTP. Attackers can downgrade connections and intercept tokens." The report includes the exact request/response that proved the vulnerability. You can run this from the middleBrick Dashboard or via the CLI: middlebrick scan https://your-feathers-api.com.

Feathersjs-Specific Remediation

Remediation in FeathersJS focuses on enforcing TLS at the Express layer and configuring Socket.io to use only secure WebSocket. Here are concrete code fixes:

1. Enforce HTTPS in Express (Feathers' underlying framework)
In your main app.js or src/ configuration, add middleware to redirect all HTTP traffic to HTTPS. If behind a reverse proxy (Nginx, Heroku), enable trust proxy so Express correctly detects the original protocol.

const express = require('@feathersjs/express');
const app = express(feathers());

// If behind a proxy (e.g., Nginx, AWS ELB)
app.enable('trust proxy');

// Redirect HTTP to HTTPS
app.use((req, res, next) => {
  if (!req.secure) {
    return res.redirect(301, `https://${req.headers.host}${req.url}`);
  }
  next();
});

2. Configure Socket.io for Secure-Only Transports
When configuring Socket.io in Feathers, explicitly set transports to ['websocket'] and enable secure cookies. This prevents any fallback to polling and ensures cookies are only sent over HTTPS.

const socketio = require('@feathersjs/socketio');

app.configure(socketio({
  // Only allow WebSocket, no polling fallback
  transports: ['websocket'],
  // Secure cookie settings (if using cookie-based sessions)
  cookie: {
    secure: true,   // Only send over HTTPS
    httpOnly: true  // Prevent client-side JS access
  }
}));

3. Harden Authentication Hooks
If using JWT, ensure tokens are never passed in query strings (which can be logged). Use the feathers-authentication library's default header-based strategy (Authorization: Bearer <token>). Also, set short token expiration and use refresh tokens.

const authentication = require('@feathersjs/authentication');
const jwt = require('@feathersjs/authentication-jwt');

app.configure(authentication({
  secret: process.env.JWT_SECRET,
  entity: 'user',
  authStrategies: ['jwt']
}));

app.configure(jwt());

4. Set Secure Headers with Helmet (Optional but Recommended)
Use the helmet middleware to set HTTP headers like Strict-Transport-Security (HSTS) which forces browsers to only use HTTPS.

const helmet = require('helmet');
app.use(helmet());
// Helmet's hsts() is enabled by default in recent versions

After applying these fixes, rescan with middleBrick. The Encryption check should now pass, and the Socket.io transport check will confirm only websocket is accepted over wss://.

Conclusion

FeathersJS' real-time capabilities, while powerful, expand the attack surface for MITM if TLS is not meticulously configured. The framework's dual exposure via REST and Socket.io means both layers must be hardened. By enforcing HTTPS redirects, restricting Socket.io to secure WebSocket, and securing authentication tokens, you eliminate the primary vectors for interception. Regular scanning with a tool like middleBrick—which actively tests both HTTP and WebSocket transports—provides ongoing assurance that your Feathers API remains protected against eavesdropping and tampering.

Frequently Asked Questions

How can I tell if my FeathersJS API is vulnerable to Man-in-the-Middle attacks?
Look for two signs: (1) Your API endpoint is accessible via http:// and does not redirect to https://, and (2) your Socket.io connection uses ws:// or falls back to HTTP polling. The quickest way to confirm is to scan your API with middleBrick; its Encryption check will flag insecure transports and weak TLS configurations specific to Feathers' Socket.io endpoint.
Does middleBrick scan WebSocket endpoints in FeathersJS applications?
Yes. middleBrick actively probes the Socket.io handshake endpoint (/socket.io/) to verify that only secure WebSocket (wss://) is accepted and that insecure transports like HTTP polling are rejected. This is part of its standard Encryption security check.