Cryptographic Failures in Feathersjs with Basic Auth
Cryptographic Failures in Feathersjs with Basic Auth
FeathersJS is a framework for real-time web applications and REST APIs. When Basic Authentication is used without additional protections, credentials are typically transmitted in an Authorization header as Basic base64(username:password). Base64 is not encryption; it is an encoding that can be decoded trivially. If the connection is not protected by TLS, credentials are exposed in transit and are vulnerable to interception. This combination represents a cryptographic failure because the protocol lacks confidentiality and, in many deployments, integrity.
During an unauthenticated scan, middleBrick tests the unauthenticated attack surface and checks whether authentication mechanisms are bypassed or improperly enforced. A FeathersJS service configured to rely solely on Basic Auth headers, without requiring HTTPS, may allow an attacker on the same network to capture credentials. Furthermore, if the application reuses or logs these headers improperly, secrets may be stored or exposed in logs or error messages. Credential exposure can lead to unauthorized access to user accounts or administrative functions, especially when the same credentials are reused across services.
Real-world attack patterns include passive sniffing on unencrypted networks and automated harvesting of logs or error responses that contain Authorization headers. OWASP API Security Top 10 category A07:2021 (Identification and Authentication Failures) aligns with this risk. PCI-DSS and other compliance frameworks require protection of credentials in transit, typically mandating strong cryptography such as TLS. middleBrick checks whether endpoints that accept Basic Auth are served over HTTPS and whether authentication is enforced consistently across routes.
An example of insecure FeathersJS configuration that exposes credentials via Basic Auth without transport protection:
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const auth = require('feathers-authentication');
const app = express(feathers());
app.configure(auth({
secret: 'supersecret',
authStrategies: ['basic'],
authProvider: {
basic: {
usernameField: 'email',
passwordField: 'password'
}
}
}));
app.use('/users', {
async find(params) {
// Vulnerable: no enforced HTTPS and no additional validation
return [{ email: '[email protected]', password: 'plaintextpassword' }];
}
});
In this example, the service advertises Basic Auth but does not enforce HTTPS. A scanner can detect whether endpoints respond with authentication challenges over non-TLS connections and whether credentials can be enumerated. The presence of Basic Auth without complementary protections such as strict transport security headers or rate limiting increases the likelihood of successful credential interception.
Basic Auth-Specific Remediation in Feathersjs — concrete code fixes
Remediation focuses on ensuring that Basic Auth credentials are never transmitted or stored in clear text and that authentication is enforced at the framework level. The primary fix is to terminate TLS at the edge and enforce HTTPS for all endpoints, particularly those using Basic Auth. Additionally, avoid storing passwords in plaintext in service files and use hashed credentials verified against a secure store.
Below is a hardened FeathersJS configuration that uses HTTPS and properly validates credentials. This example assumes you have a TLS certificate and key available.
const fs = require('fs');
const https = require('https');
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const auth = require('feathers-authentication');
const app = express(feathers());
// Enforce HTTPS server with TLS
const server = https.createServer({
key: fs.readFileSync('/path/to/server.key'),
cert: fs.readFileSync('/path/to/server.crt')
}, app);
app.configure(auth({
secret: process.env.AUTH_SECRET,
authStrategies: ['basic'],
authProvider: {
basic: {
usernameField: 'email',
passwordField: 'password',
// Verify credentials against a secure data source
verify: async (username, password) => {
const user = await getUserByEmail(username);
if (!user) return null;
const valid = await comparePassword(password, user.passwordHash);
return valid ? user : null;
}
}
}
}));
// Use hooks to enforce authentication on services
app.use('/secure-data', {
async find(params) {
// Only called after authentication hook passes
return db.find({ where: { userId: params.user.id } });
}
});
app.service('secure-data').hooks({
before: {
all: [app.authentication.hooks.authenticate(['basic'])]
}
});
server.listen(443, () => console.log('HTTPS server running on port 443'));
Additional remediation steps include:
- Redirect all HTTP traffic to HTTPS using a reverse proxy or load balancer.
- Store passwords using a strong adaptive hashing algorithm such as bcrypt or argon2; never store or log raw passwords.
- Set HTTP headers like
Strict-Transport-SecurityandContent-Security-Policyto mitigate downgrade attacks. - Apply rate limiting to authentication endpoints to reduce brute-force risk; middleBrick’s Rate Limiting check can help identify missing controls.
- Ensure that no Authorization headers are logged or exposed in error messages by sanitizing logs.
These changes ensure that credentials are protected in transit and that authentication is integrated with the application’s security model rather than being a superficial header check.