CWE-287 in APIs
What is CWE-287?
CWE-287 describes Improper Authentication — a weakness where an attacker can bypass authentication mechanisms or authenticate without proper credentials. This fundamental security flaw allows unauthorized access to systems, data, or functionality that should be protected.
The weakness manifests when authentication mechanisms fail to properly verify the identity of users or services. This can occur through flawed logic, missing checks, weak credential handling, or bypassing authentication entirely. When successful, attackers gain access to resources they shouldn't have, potentially exposing sensitive data, manipulating systems, or escalating privileges.
Common examples include missing authentication checks on API endpoints, weak session management, hardcoded credentials, or authentication bypass through parameter manipulation. The impact ranges from data exposure to complete system compromise, depending on what resources the attacker can access once authenticated.
CWE-287 in API Contexts
APIs face unique authentication challenges compared to traditional web applications. The stateless nature of many APIs, the need for machine-to-machine communication, and the variety of client types (web apps, mobile apps, IoT devices) create multiple attack surfaces for authentication bypass.
Common API-specific manifestations include:
- Missing authentication on sensitive endpoints — API routes that handle user data or administrative functions without requiring authentication tokens
- Weak token validation — accepting expired, malformed, or invalid JWT tokens without proper verification
- Authentication bypass through parameter manipulation — modifying request parameters to skip authentication checks
- Improper role-based access control — authenticated users accessing resources belonging to other users
- Credential stuffing vulnerabilities — APIs lacking rate limiting or account lockout mechanisms
Consider an API endpoint that returns user profile information. If the endpoint accepts a user ID parameter but doesn't verify that the authenticated user owns that profile, an attacker can enumerate user IDs and access anyone's data. This is a classic example of broken authentication in APIs.
Detection
Detecting improper authentication requires both manual code review and automated scanning. For APIs, black-box scanning can identify many authentication weaknesses without access to source code.
Manual detection approaches:
- Code review for authentication checks on all sensitive endpoints
- Testing authentication bypass by removing or modifying tokens
- Verifying proper session management and token validation
- Checking for hardcoded credentials or default passwords
- Testing role-based access controls with different user permissions
Automated scanning with middleBrick:
middleBrick's Authentication check specifically tests for CWE-287 by attempting to access protected resources without valid credentials. The scanner tries multiple authentication bypass techniques including:
- Removing authentication headers entirely
- Using expired or malformed tokens
- Modifying authentication parameters
- Testing for default credentials
The scan takes 5-15 seconds and returns a security risk score with detailed findings. If authentication is missing or weak, middleBrick flags the specific endpoints and provides severity ratings with remediation guidance.
For example, if an API endpoint at /api/users/profile returns user data without requiring authentication, middleBrick will detect this as a critical vulnerability and suggest implementing proper authentication checks.
Remediation
Fixing improper authentication requires implementing robust authentication mechanisms and ensuring they're applied consistently across all sensitive endpoints. Here are practical remediation approaches with code examples.
1. Implement Proper Authentication Middleware
// Node.js/Express example
const jwt = require('jsonwebtoken');
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Access denied. No token provided.' });
}
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) {
return res.status(403).json({ error: 'Invalid or expired token.' });
}
req.user = user;
next();
});
}
// Apply to protected routes
app.get('/api/users/profile', authenticateToken, (req, res) => {
res.json({ user: req.user });
});
2. Validate JWT Tokens Properly
// Python/Flask example
from flask import request, jsonify
from functools import wraps
import jwt
from datetime import datetime, timedelta
def token_required(f):
@wraps(f)
def decorated(*args, **kwargs):
token = request.headers.get('x-access-token')
if not token:
return jsonify({'error': 'Token is missing'}), 401
try:
data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'])
current_user = User.query.get(data['user_id'])
except jwt.ExpiredSignatureError:
return jsonify({'error': 'Token has expired'}), 403
except jwt.InvalidTokenError:
return jsonify({'error': 'Invalid token'}), 403
return f(current_user, *args, **kwargs)
return decorated
@app.route('/api/profile')
@token_required
def get_profile(current_user):
return jsonify(current_user.to_dict())
3. Implement Role-Based Access Control
// Check user permissions before accessing resources
function checkOwnership(req, res, next) {
const resourceOwnerId = req.resource.ownerId;
const authenticatedUserId = req.user.id;
if (resourceOwnerId !== authenticatedUserId) {
return res.status(403).json({
error: 'Access denied. You can only access your own resources.'
});
}
next();
}
// Combined authentication and authorization
app.get('/api/users/:id/profile',
authenticateToken,
checkOwnership,
(req, res) => {
res.json({ user: req.user });
});
4. Use Strong Password Policies and Multi-Factor Authentication
// Password strength validation
function validatePassword(password) {
const minLength = 12;
const hasLower = /[a-z]/.test(password);
const hasUpper = /[A-Z]/.test(password);
const hasDigit = /[0-9]/.test(password);
const hasSpecial = /[!@#$%^&*()_+=-]/.test(password);
if (password.length < minLength) return false;
if (!hasLower || !hasUpper || !hasDigit || !hasSpecial) return false;
return true;
}
// Rate limiting to prevent brute force attacks
const rateLimit = require('express-rate-limit');
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // limit each IP to 5 requests per windowMs
message: 'Too many login attempts. Please try again later.'
});
app.post('/api/login', loginLimiter, (req, res) => {
// authentication logic
});
5. Test Authentication Thoroughly
After implementing fixes, test all authentication scenarios:
- Attempt access without authentication
- Try expired/invalid tokens
- Test with different user roles
- Verify session timeout behavior
- Test for authentication bypass through parameter manipulation
middleBrick can help verify your fixes by re-scanning the API and confirming that authentication weaknesses have been resolved.