HIGH CWE-308 Authentication

CWE-308 in APIs

CWE ID
CWE-308
Category
Authentication
Severity
MEDIUM
Short Name
Single Factor

What is Cwe 308?

CWE-308: Use of Single-factor Authentication is a weakness where a system relies solely on one authentication factor—typically a password—without requiring additional verification methods. This creates a significant security vulnerability because if an attacker compromises the single factor, they gain full access to the system.

The weakness manifests when systems authenticate users based on only one of these factors: something you know (password), something you have (security token), or something you are (biometric). By using just one factor, the system lacks the layered defense that multi-factor authentication (MFA) provides. An attacker who obtains a user's password through phishing, credential stuffing, or database breaches can immediately impersonate that user without any additional barriers.

Cwe 308 in API Contexts

In API environments, CWE-308 appears when APIs accept only password-based authentication without additional verification. This is particularly dangerous because APIs often handle sensitive operations like financial transactions, data access, and system administration.

Common API manifestations include:

  • APIs that accept only API keys or basic authentication without requiring second factors
  • OAuth implementations that skip step-up authentication for high-risk operations
  • Session-based APIs that rely solely on cookies without additional verification
  • Administrative APIs accessible with single-factor credentials
  • Database APIs exposed with only password protection

The risk escalates when APIs handle privileged operations. For example, an API endpoint that allows password changes or fund transfers should require additional verification beyond just the user's primary credentials. Without this, attackers who steal credentials can immediately perform destructive actions.

Detection

Detecting CWE-308 requires examining authentication mechanisms and testing for single-factor dependencies. Manual code review can identify authentication patterns, but automated scanning provides comprehensive coverage.

middleBrick's authentication scanning specifically tests for single-factor authentication weaknesses by analyzing API endpoints and their authentication requirements. The scanner examines:

  • Authentication method diversity (checking for only password-based systems)
  • Step-up authentication requirements for sensitive operations
  • Session management and token validation patterns
  • Administrative endpoint protection levels

During scanning, middleBrick tests whether APIs require multiple authentication factors for different operations. For instance, it checks if password changes or account modifications require additional verification beyond the initial login. The scanner also analyzes OpenAPI specifications to identify endpoints that should implement MFA but don't.

Security teams should also look for indicators like APIs that accept only basic auth, endpoints without rate limiting on authentication attempts, and administrative interfaces accessible with single credentials.

Remediation

Fixing CWE-308 involves implementing multi-factor authentication and applying the principle of least privilege. Here's how to remediate this weakness in API implementations:

1. Implement Multi-Factor Authentication

// Before: Single-factor authentication only
app.post('/login', (req, res) => {
const { username, password } = req.body;
authenticateUser(username, password)
.then(user => res.json({ token: generateToken(user) }))
.catch(err => res.status(401).json({ error: 'Invalid credentials' }));
});

// After: Multi-factor authentication
app.post('/login', (req, res) => {
const { username, password } = req.body;
authenticateUser(username, password)
.then(user => {
// Send MFA code via SMS, email, or authenticator app
const mfaCode = generateMFACode();
sendMFACode(user.email, mfaCode);
res.json({ mfaRequired: true, userId: user.id });
})
.catch(err => res.status(401).json({ error: 'Invalid credentials' }));
});

app.post('/verify-mfa', (req, res) => {
const { userId, mfaCode } = req.body;
verifyMFACode(userId, mfaCode)
.then(() => res.json({ token: generateToken(user) }))
.catch(err => res.status(401).json({ error: 'Invalid MFA code' }));
});

2. Apply Step-up Authentication

# Before: Single authentication for all operations
@app.route('/api/transfer', methods=['POST'])
def transfer_funds():
user = get_authenticated_user()
# No additional verification for high-risk operation
return execute_transfer(user, request.json)

# After: Step-up authentication for sensitive operations
@app.route('/api/transfer', methods=['POST'])
def transfer_funds():
user = get_authenticated_user()

# Require additional verification for high-risk operations
if not verify_step_up_auth(user):
return jsonify({
'error': 'Additional verification required',
'step_up_required': True
}), 403

return execute_transfer(user, request.json)

def verify_step_up_auth(user):
# Check for recent MFA, biometric, or security question verification
if user.last_mfa_time > datetime.now() - timedelta(minutes=5):
return True

# Or require fresh MFA code
return verify_mfa_code(user.id, request.headers.get('X-MFA-Code'))

3. Implement API Key Rotation and Time-based Tokens

// Before: Static API keys
func authenticateAPIKey(key string) (*User, error) {
user, err := db.GetUserByAPIKey(key)
if err != nil { return nil, err }
return user, nil
}

// After: Time-based, rotating tokens
func authenticateBearerToken(token string) (*User, error) {
claims, err := jwt.ParseWithClaims(token, &jwt.StandardClaims{},

if err != nil || claims.ExpiresAt < time.Now().Unix() {
return nil, errors.New("invalid or expired token")
}

return db.GetUserByID(claims.Subject)
}

// Require re-authentication periodically
func requireReauth(user *User) bool {
return user.last_auth < time.Now().Add(-24 * time.Hour)
}

4. Use Adaptive Authentication

@Service
public class AdaptiveAuthService {

public AuthenticationResult authenticate(UserCredentials creds) {
// Basic authentication
User user = userRepository.findByUsername(creds.getUsername());
if (!passwordEncoder.matches(creds.getPassword(), user.getPassword())) {
return AuthenticationResult.failure("Invalid credentials");
}

// Risk assessment
RiskLevel risk = assessRisk(user, creds);

if (risk == RiskLevel.HIGH) {
// High-risk operations require additional factors
if (!verifySecondFactor(user, creds.getSecondFactor())) {
return AuthenticationResult.failure("Additional verification required");
}
} else if (risk == RiskLevel.CRITICAL) {
// Critical operations require step-up authentication
return requireStepUpAuthentication(user);
}

return AuthenticationResult.success(generateToken(user));
}

private RiskLevel assessRisk(User user, UserCredentials creds) {
if (isHighRiskOperation(creds.getEndpoint())) {
return RiskLevel.CRITICAL;
}
return RiskLevel.HIGH;
}
}
}

Frequently Asked Questions

What's the difference between CWE-308 and CWE-309?
CWE-308 (Use of Single-factor Authentication) involves relying on only one authentication factor, while CWE-309 (Use of Password System for Primary Authentication) is broader and includes systems that use passwords as the primary method even if other factors exist. CWE-308 is specifically about the absence of multi-factor authentication, whereas CWE-309 covers poor password practices even in multi-factor systems.
How does middleBrick detect CWE-308 in APIs?
middleBrick scans API endpoints to identify authentication mechanisms and tests whether they rely solely on single-factor authentication. The scanner examines authentication headers, token validation, and endpoint protection levels. It also analyzes OpenAPI specifications to identify endpoints that should implement MFA for sensitive operations but don't. The tool provides specific findings about which endpoints are vulnerable to single-factor authentication weaknesses.