Missing Authentication in Feathersjs
How Missing Authentication Manifests in Feathersjs
Missing authentication in Feathersjs applications creates critical security vulnerabilities that attackers can exploit to gain unauthorized access to sensitive data and functionality. Feathersjs's real-time capabilities and service-based architecture introduce unique attack vectors that developers must understand.
The most common manifestation occurs in service methods that lack authentication hooks. Consider a Feathersjs service that manages user data:
class UserService {
async find() {
return await this.Model.find({});
}
async get(id) {
return await this.Model.findById(id);
}
async create(data) {
return await this.Model.create(data);
}
}Without authentication hooks, any client can call these methods. An attacker could enumerate user IDs and access private profiles:
// GET /users/1234
// GET /users/5678
// No authentication required!Feathersjs's real-time features create additional risks. Socket.io connections can bypass traditional REST authentication:
const app = feathers();
app.configure(feathers.socketio());
app.service('messages').on('created', (data) => {
// Broadcast to ALL connected clients
app.service('messages').emit('created', data);
});
Without authentication middleware, any socket.io client can subscribe to channels and receive real-time updates about data they shouldn't access.
Feathersjs's hook system, while powerful, can be misconfigured. A common mistake is applying authentication hooks only to certain methods:
const { authenticate } = require('@feathersjs/authentication').hooks;
const userHooks = {
before: {
create: [authenticate('jwt')],
update: [authenticate('jwt')],
patch: [authenticate('jwt')],
remove: [authenticate('jwt')]
}
};
This configuration allows unauthenticated users to call find() and get() methods, potentially exposing all user records.
Feathersjs applications often integrate with external APIs or microservices. Missing authentication in these integrations creates supply chain vulnerabilities:
class PaymentService {
async processPayment(paymentData) {
// No authentication to verify caller identity
const result = await externalApi.process(paymentData);
return result;
}
}An attacker could invoke payment processing without proper authorization, potentially causing financial damage or data exposure.
Feathersjs-Specific Detection
Detecting missing authentication in Feathersjs requires examining both the application structure and runtime behavior. middleBrick's black-box scanning approach is particularly effective for Feathersjs applications since it tests the actual attack surface without requiring source code access.
middleBrick scans Feathersjs APIs by sending requests to all service endpoints and analyzing responses. For a Feathersjs application running at https://api.example.com, middleBrick tests:
middlebrick scan https://api.example.com
The scanner identifies Feathersjs-specific patterns like:
- Service endpoints following REST conventions (
/users,/messages,/posts) - Feathersjs error responses with specific formatting
- Socket.io endpoints and real-time channels
- WebSocket connections on standard Feathersjs ports
middleBrick's authentication check specifically tests for missing authentication by attempting unauthenticated access to protected endpoints. It analyzes responses for indicators like:
{
"endpoint": "/api/users",
"method": "GET",
"response_status": 200,
"risk": "high",
"finding": "Missing authentication allows unauthenticated access to user data",
"remediation": "Add authentication hooks to all service methods"
}For Feathersjs applications using JWT authentication, middleBrick tests token validation by sending requests with various token states (expired, malformed, missing). It also checks for common misconfigurations like:
- Authentication hooks applied only to certain HTTP methods
- Missing authentication on service methods that should be protected
- Hardcoded credentials or API keys in source code
- Excessive data exposure in error messages
middleBrick's OpenAPI/Swagger analysis is particularly valuable for Feathersjs applications. Many Feathersjs developers generate API specs from their service definitions:
openapi: 3.0.0
info:
title: Feathersjs API
version: 1.0.0
paths:
/users:
get:
summary: Get all users
responses:
'200':
description: Successful response
middleBrick compares the spec definitions with actual runtime behavior, identifying discrepancies where endpoints appear protected in documentation but are actually accessible.
Feathersjs-Specific Remediation
Remediating missing authentication in Feathersjs requires a systematic approach using Feathersjs's built-in authentication and authorization features. The first step is implementing authentication hooks at the service level:
const { authenticate } = require('@feathersjs/authentication').hooks;
const userService = {
Model: UserModel,
hooks: {
before: {
all: [authenticate('jwt')],
find: [authenticate('jwt')],
get: [authenticate('jwt')],
create: [authenticate('jwt')],
update: [authenticate('jwt')],
patch: [authenticate('jwt')],
remove: [authenticate('jwt')]
}
}
};
This configuration ensures all service methods require valid JWT tokens. For applications with different authentication requirements per method, use conditional hooks:
const { authenticate } = require('@feathersjs/authentication').hooks;
const hooks = {
before: {
find: [authenticate('jwt')],
get: [authenticate('jwt')],
create: [authenticate('jwt')],
update: [authenticate('jwt')],
patch: [authenticate('jwt')],
remove: [authenticate('jwt')]
}
};
Feathersjs's authorization hooks provide fine-grained control over what authenticated users can access:
const { iff, isProvider, fastJoin } = require('feathers-hooks-common');
const authorization = {
before: {
all: [iff(isProvider('external'), authenticate('jwt'))]
},
after: {
find: [fastJoin(computedResults)],
get: [fastJoin(computedResults)]
}
};
For real-time authentication, configure socket.io middleware:
const io = require('socket.io');
const { authenticate } = require('@feathersjs/authentication');
const ioServer = io(httpServer);
ioServer.use((socket, next) => {
const { token } = socket.handshake.query;
if (!token) return next(new Error('Authentication required'));
authenticate('jwt', { token }, (err, payload) => {
if (err) return next(err);
socket.feathers = payload;
next();
});
});
Implement role-based access control (RBAC) for different user types:
const { iff, isProvider, fastJoin } = require('feathers-hooks-common');
const rbac = {
before: {
all: [iff(isProvider('external'), authenticate('jwt'))],
find: [checkPermissions('read:data')],
create: [checkPermissions('write:data')],
update: [checkPermissions('admin:data')],
patch: [checkPermissions('write:data')],
remove: [checkPermissions('admin:data')]
}
};
function checkPermissions(requiredPermission) {
return async (context) => {
const { user } = context.params;
if (!user.permissions.includes(requiredPermission)) {
throw new Error('Insufficient permissions');
}
};
}
middleBrick's CLI tool helps verify authentication implementation:
middlebrick scan https://api.example.com --auth-test
Integrate authentication testing into your CI/CD pipeline with the GitHub Action:
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run middleBrick security scan
uses: middlebrick/middlebrick-action@v1
with:
url: 'https://api.example.com'
fail-on-severity: high
token: ${{ secrets.MIDDLEBRICK_TOKEN }}
This configuration ensures authentication vulnerabilities are caught before deployment, preventing missing authentication issues from reaching production.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |