MEDIUM side channel attackfeathersjs

Side Channel Attack in Feathersjs

How Side Channel Attack Manifests in Feathersjs

Side channel attacks in Feathersjs exploit timing differences and error responses to infer sensitive information about your application's data and structure. The most common manifestation occurs through response timing variations during authentication and data retrieval operations.

Consider a Feathersjs authentication endpoint that checks user credentials. When an attacker submits a username, the response time differs based on whether the username exists in the database. If the username exists, the system performs password verification (bcrypt comparison), which takes measurable time. If the username doesn't exist, the system returns immediately. This timing difference allows attackers to enumerate valid usernames.

async function verifyPassword(username, password) {
  const user = await users.find({ query: { email: username } }).then(r => r.data[0]);
  
  // Timing leak: exists() vs. non-existent users have different execution paths
  if (!user) {
    return false; // Immediate return
  }
  
  // bcrypt comparison takes 100-500ms, creating measurable timing difference
  return await bcrypt.compare(password, user.password);
}

Another Feathers-specific side channel occurs through service method differences. When querying for non-existent resources versus existing ones with different permissions, the response structure and HTTP status codes vary:

// Vulnerable: Different responses reveal resource existence
app.service('users').get(id)
  .then(user => res.json(user))           // 200 OK - resource exists
  .catch(err => {
    if (err.name === 'NotFound') {
      res.status(404).json({ error: 'Not found' }); // 404 - resource doesn't exist
    } else {
      res.status(401).json({ error: 'Unauthorized' }); // 401 - exists but unauthorized
    }
  });

Feathersjs's real-time features via Socket.io create additional side channels. The presence or absence of events on channels can reveal whether users exist and their online status:

const userChannel = app.channel((data) => {
  // Timing and existence leak: checking if user exists in channel
  return app.service('users').get(data.userId)
    .then(() => true)  // User exists - channel created
    .catch(() => false); // User doesn't exist - no channel
});

Feathersjs-Specific Detection

Detecting side channel vulnerabilities in Feathersjs requires both manual code review and automated scanning. The middleBrick scanner specifically identifies timing-based and information-disclosure vulnerabilities in Feathers applications.

middleBrick's detection methodology for Feathersjs includes:

  • Timing analysis: Measures response time variations across similar endpoints to identify potential timing side channels
  • Response structure analysis: Detects inconsistent error responses that reveal system state
  • Authentication flow analysis: Examines login and verification endpoints for timing leaks
  • Real-time channel analysis: Scans Socket.io channels for existence-revealing patterns
  • Service method analysis: Reviews get(), find(), and other service methods for information disclosure

Using middleBrick's CLI for Feathersjs scanning:

npx middlebrick scan https://your-feathersjs-app.com/api

# Or scan specific Feathers endpoints
npx middlebrick scan https://your-feathersjs-app.com/api/users
npx middlebrick scan https://your-feathersjs-app.com/socket.io/

The scanner analyzes your Feathersjs application's runtime behavior, looking for patterns like:

// middleBrick detects this pattern:
if (await userExists(email)) {
  // Different code path than non-existent users
  return await verifyPassword(email, password);
} else {
  return false; // Immediate return creates timing difference
}

Manual detection techniques for Feathersjs developers:

// Use performance hooks to identify timing variations
app.service('users').hooks({
  before: {
    get: async (context) => {
      const start = process.hrtime.bigint();
      // Your logic here
      const end = process.hrtime.bigint();
      const duration = Number(end - start) / 1e6;
      
      // Log and analyze timing differences
      if (duration > 100) console.log('Potential timing issue detected');
    }
  }
});

Feathersjs-Specific Remediation

Remediating side channel vulnerabilities in Feathersjs requires implementing consistent response patterns and timing across all code paths. Here are Feathers-specific solutions:

1. Constant-time authentication:

// Secure: Constant-time comparison regardless of user existence
async function verifyPassword(username, password) {
  // Always perform a database lookup
  const user = await users.find({ query: { email: username } }).then(r => r.data[0]) || {
    // Return a dummy user with hashed dummy password
    password: process.env.DUMMY_HASHED_PASSWORD
  };
  
  // Always perform bcrypt comparison
  const valid = await bcrypt.compare(password, user.password);
  
  // Always perform same operations regardless of outcome
  await logAuthenticationAttempt(username, valid);
  
  return valid;
}

2. Consistent error responses:

// Secure: Uniform response structure
app.service('users').hooks({
  get: async (context) => {
    try {
      const result = await context.app.service('users').get(context.id);
      context.result = result;
    } catch (error) {
      // Always return same structure, different status only
      context.result = { error: 'Resource not accessible' };
      context.statusCode = error.name === 'NotFound' ? 404 : 401;
    }
  }
});

3. Rate limiting to mitigate timing attacks:

const rateLimit = require('express-rate-limit');

// Apply rate limiting to authentication endpoints
app.use('/api/authentication', rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // limit each IP to 5 requests per windowMs
  message: 'Too many authentication attempts, please try again later.',
  standardHeaders: true,
  legacyHeaders: false,
}));

// Add to Feathers service
app.service('authentication').hooks({
  before: {
    create: async (context) => {
      // Add artificial delay to normalize timing
      await new Promise(resolve => setTimeout(resolve, 200));
    }
  }
});

4. Secure real-time channels:

// Secure: Don't reveal user existence through channel presence
const userChannel = app.channel((data) => {
  // Always return a channel, don't reveal existence
  const channel = app.channel("authenticated");
  
  // Filter events server-side instead of channel presence
  return channel.filter((message) => {
    return message.userId === data.userId;
  });
});

Frequently Asked Questions

How can I test if my Feathersjs app has side channel vulnerabilities?
Use middleBrick's automated scanner to analyze your Feathersjs endpoints for timing variations and inconsistent error responses. Additionally, manually test authentication endpoints by measuring response times for valid vs invalid usernames, and verify that error responses don't reveal whether resources exist.
Does middleBrick detect side channel attacks in Feathersjs real-time features?
Yes, middleBrick's scanner analyzes Socket.io channels and real-time event patterns in Feathersjs applications. It specifically looks for channel creation patterns that reveal user existence, event timing variations, and inconsistent real-time responses that could leak sensitive information.