HIGH brute force attackfeathersjsfirestore

Brute Force Attack in Feathersjs with Firestore

Brute Force Attack in Feathersjs with Firestore — how this specific combination creates or exposes the vulnerability

A brute force attack against a Feathersjs service backed by Firestore typically targets authentication endpoints or user lookup routes. Feathersjs, by default, exposes a REST API and a real-time API. If authentication is implemented with local strategy (e.g., using @feathersjs/authentication-local), the login route (POST /authentication) accepts user-supplied identifiers such as email or username. Without adequate protections, an attacker can systematically submit credential guesses to identify valid accounts.

In this stack, Firestore serves as the identity store. Queries like get() or where() are used to retrieve user records by email or username. A common misconfiguration is returning a distinct response when a user is found versus when they are not. If the endpoint leaks whether an account exists (e.g., 404 vs 200 with a generic invalid credentials message), attackers can enumerate valid users and then focus attempts on those accounts. Firestore security rules do not prevent application-layer logic from leaking existence; they govern document read/write permissions, not rate or behavior semantics.

Feathersjs plugins such as authentication-local provide hooks for hashing and verifying passwords, but they do not enforce rate limiting or account lockout by default. Without explicit protections, a local endpoint becomes susceptible to online brute force. Attackers may also probe for weak passwords using credential lists, particularly if the service lacks request throttling. Supplementary risks include token replay if tokens are long-lived or improperly scoped, and the absence of multi-factor authentication increases the impact of successful guesses.

An additional vector arises from public or misconfigured Firestore rules combined with Feathersjs services that expose user collections. If a collection is readable without strict validation, attackers may harvest user metadata (e.g., usernames, profile fields) to refine guesses. Even when authentication uses hashed passwords, information leakage in error messages or response timing can aid enumeration. The combination of a permissive Firestore rule set and a Feathersjs endpoint that does not uniformly apply rate controls or masking compounds the problem.

Real-world patterns include attackers using scripts that iterate over common passwords against discovered accounts, leveraging predictable identifiers (sequential IDs or known email formats), and exploiting inconsistent error handling across development and production. The OWASP API Security Top 10 category ‘2023-A07: Identification and Authentication Failures’ maps to these risks. Tools like middleBrick can surface issues such as missing rate limiting, weak input validation on login fields, and inconsistent response behavior through its 12 security checks, including Authentication, Input Validation, and Rate Limiting assessments.

Firestore-Specific Remediation in Feathersjs — concrete code fixes

Remediation focuses on hardening authentication flows, standardizing responses, and enforcing rate controls. Ensure login endpoints return the same status code and generic message regardless of whether the user exists. Use constant-time comparison for password verification where possible, and avoid leaking timing information via Firestore query patterns.

Example: a secured Feathersjs authentication hook with consistent response behavior and safe Firestore querying.

const { AuthenticationService } = require('@feathersjs/authentication');
const { local } = require('@feathersjs/authentication-local');
const { Forbidden } = require('@feathersjs/errors');

app.configure(authentication({
  secret: process.env.AUTH_SECRET,
  strategies: ['local'],
  path: '/authentication'
}));

app.use('/authentication', local({
  async verify(email, password) {
    const usersService = app.service('users');
    // Always query for a single document by normalized email to reduce timing variance
    const user = await usersService.Model.findOne({
      where: { email: email.toLowerCase().trim() },
      limit: 1
    });
    if (!user) {
      // Simulate password hashing work to reduce timing differences
      await fakeHash(password);
      throw new Forbidden('Invalid credentials');
    }
    const isValid = await usersService.app.passport.verifyPassword(user, password);
    if (!isValid) {
      throw new Forbidden('Invalid credentials');
    }
    return user;
  }
}));

async function fakeHash(input) {
  // Placeholder to mitigate timing differences
  return Promise.resolve();
}

Example: Firestore security rules that restrict excessive reads and enforce structured access, complementing application-level rate limiting.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
      // Prevent public enumeration by disallowing list queries without auth
    }
    // Define specific query constraints to avoid broad scans
    match /publicProfiles/{docId} {
      allow read: if request.auth != null; // or more restrictive conditions
    }
  }
}

Example: Adding rate limiting using a memory store or external provider in a before hook to protect authentication endpoints.

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

app.use('/authentication', rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // limit each IP to 5 login attempts per windowMs
  key: 'ip',
  skipSuccessfulRequests: false,
  handler: function(context) {
    throw new Forbidden('Too many attempts, try again later');
  }
}));

Additional guidance: Use strong password policies, enable multi-factor authentication where feasible, and monitor for anomalous patterns (many failed attempts from the same IP or across accounts). Configure middleBrick’s free tier to run scans periodically; the Starter plan supports continuous monitoring and integrates with GitHub Actions to gate deployments if risk scores degrade. Findings from Authentication, Rate Limiting, and Input Validation checks help prioritize fixes.

Frequently Asked Questions

Why does consistent error messaging matter for brute force mitigation in Feathersjs with Firestore?
Returning distinct errors (e.g., user not found vs invalid password) allows attackers to enumerate valid accounts. A uniform response code and message prevent information leakage during credential guessing.
Can Firestore security rules alone stop brute force attacks on a Feathersjs service?
No. Firestore rules manage document-level permissions but do not enforce rate limits or masking of authentication behavior. Application-level protections such as rate limiting and consistent error handling are required.