HIGH broken access controlmutual tls

Broken Access Control with Mutual Tls

How Broken Access Control Manifests in Mutual Tls

Broken Access Control in Mutual TLS environments occurs when the mutual authentication process fails to properly validate the client's identity and authorization level before granting access to protected resources. Unlike basic TLS where only the server is authenticated, Mutual TLS requires both parties to present valid certificates, creating a false sense of security if access control checks are not properly implemented.

A common vulnerability arises when developers assume that a successful Mutual TLS handshake automatically grants appropriate permissions. This leads to scenarios where any client with a valid certificate can access resources they shouldn't have access to. For example, a financial API might authenticate a client certificate but fail to check whether that client is authorized to access sensitive account data.

Consider this vulnerable Mutual TLS endpoint:

app.get('/api/transactions', (req, res) => {
  // Only checks if client cert exists, not WHO the client is
  if (!req.client.authorized) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  
  // No authorization check - any authenticated client can see all transactions
  const transactions = db.getAllTransactions();
  res.json(transactions);
});

The vulnerability here is that the code only verifies the presence of a client certificate but never validates the client's identity against an authorization database or policy store. Any client with a valid certificate from the trusted CA can access all transaction data.

Another manifestation involves improper certificate validation logic. Developers might check certificate properties incorrectly, such as:

app.get('/api/sensitive-data', (req, res) => {
  const cert = req.client.getPeerCertificate();
  
  // Vulnerable: only checks CN, not the full certificate chain or revocation status
  if (cert.subject.CN !== 'trusted-client') {
    return res.status(403).json({ error: 'Access denied' });
  }
  
  // Even if CN matches, this doesn't verify the client's actual permissions
  res.json(sensitiveData);
});

This code is vulnerable because it relies on a single certificate property (Common Name) rather than implementing proper role-based access control. A compromised certificate with the same CN could gain unauthorized access.

Mutual Tls-Specific Detection

Detecting Broken Access Control in Mutual TLS requires both automated scanning and manual code review. The most effective approach combines runtime testing with static analysis of the authentication and authorization logic.

Automated detection tools like middleBrick can identify Mutual TLS-specific vulnerabilities by testing unauthenticated endpoints that should require client certificates. The scanner attempts to access protected resources without presenting a client certificate, then with different client certificates to identify authorization gaps. For Mutual TLS endpoints, middleBrick performs:

  • Certificate validation bypass attempts
  • Authorization bypass tests with valid but unauthorized certificates
  • Property authorization checks for certificate-based access controls
  • Input validation testing for certificate-related parameters
  • SSRF testing to ensure certificate validation can't be bypassed through proxying

Here's how you can manually test for Mutual TLS Broken Access Control:

# Test without client certificate (should fail)
curl -k https://api.example.com/protected --cacert ca.crt

# Test with valid certificate but different identity
openssl req -x509 -newkey rsa:2048 -keyout client2.key -out client2.crt -days 365 -nodes
curl -k https://api.example.com/protected --key client2.key --cert client2.crt --cacert ca.crt

# Test with revoked certificate
curl -k https://api.example.com/protected --cert client-revoked.crt --key client-revoked.key --cacert ca.crt

During runtime testing, monitor for these indicators of Broken Access Control:

IndicatorWhat to Look ForRisk Level
Certificate-only authenticationEndpoints that only check certificate presence, not identityHigh
Static CN validationCode that only validates certificate Common NameHigh
Missing revocation checksNo certificate revocation list (CRL) or OCSP verificationMedium
Role-based access missingNo mapping between certificate properties and user rolesCritical

For comprehensive Mutual TLS security assessment, use middleBrick's CLI to scan your API endpoints:

npx middlebrick scan https://api.example.com --output json --verbose

# Or integrate into CI/CD
middlebrick scan https://staging-api.example.com --fail-below B

The scanner will identify if your Mutual TLS implementation has broken access control patterns and provide specific remediation guidance for each finding.

Mutual Tls-Specific Remediation

Fixing Broken Access Control in Mutual TLS requires implementing proper certificate validation and authorization checks. The solution involves three layers: certificate validation, identity mapping, and role-based access control.

First, implement comprehensive certificate validation:

const fs = require('fs');
const https = require('https');

const options = {
  cert: fs.readFileSync('server.crt'),
  key: fs.readFileSync('server.key'),
  ca: [fs.readFileSync('ca.crt')],
  requestCert: true,
  rejectUnauthorized: true,
  checkServerIdentity: (host, cert) => {
    // Additional server identity validation
    if (cert.subject.CN !== host) {
      throw new Error('Certificate subject does not match host');
    }
  }
};

https.createServer(options, (req, res) => {
  const cert = req.socket.getPeerCertificate();
  
  // Verify certificate chain and revocation
  if (!verifyCertificateChain(cert)) {
    return res.writeHead(403).end('Invalid certificate chain');
  }
  
  // Check certificate revocation status
  if (!checkCertificateRevocation(cert)) {
    return res.writeHead(403).end('Certificate revoked');
  }
  
  // Map certificate to identity
  const identity = mapCertificateToIdentity(cert);
  if (!identity) {
    return res.writeHead(403).end('Unknown client identity');
  }
  
  // Perform authorization check
  if (!authorizeAccess(identity, req.url)) {
    return res.writeHead(403).end('Insufficient permissions');
  }
  
  // Grant access
  res.writeHead(200);
  res.end('Authorized access granted');
}).listen(443);

function verifyCertificateChain(cert) {
  // Implement chain verification logic
  // Check if certificate is signed by trusted CA
  // Verify intermediate certificates
  return true;
}

function checkCertificateRevocation(cert) {
  // Implement CRL or OCSP checking
  // Return false if certificate is revoked
  return true;
}

function mapCertificateToIdentity(cert) {
  // Extract identity from certificate properties
  // This could be from SAN, CN, or custom extensions
  return {
    id: cert.subject.CN,
    roles: extractRolesFromCertificate(cert),
    organization: cert.subject.O
  };
}

function authorizeAccess(identity, resource) {
  // Implement role-based access control
  const permissions = {
    'finance-admin': ['transactions', 'reports', 'users'],
    'finance-viewer': ['transactions', 'reports'],
    'external-partner': ['public-data']
  };
  
  const requiredPermission = resource.split('/')[2];
  return identity.roles.some(role => 
    permissions[role]?.includes(requiredPermission)
  );
}

function extractRolesFromCertificate(cert) {
  // Extract roles from certificate extensions or SAN
  // This is application-specific
  const roles = [];
  
  // Check for custom extension containing roles
  if (cert.extensions) {
    cert.extensions.forEach(ext => {
      if (ext.name === 'subjectAltName') {
        // Parse SAN for role information
        const sanRoles = parseRolesFromSAN(ext.value);
        roles.push(...sanRoles);
      }
    });
  }
  
  return roles;
}

function parseRolesFromSAN(sanValue) {
  // Parse roles from SAN field
  // Format: DNS:role1.example.com,DNS:role2.example.com
  const roles = [];
  const parts = sanValue.split(',');
  parts.forEach(part => {
    if (part.startsWith('DNS:')) {
      const domain = part.substring(4);
      const roleMatch = domain.match(/role-([^.]+)//);
      if (roleMatch) {
        roles.push(roleMatch[1]);
      }
    }
  });
  return roles;
}

For Java Spring Boot applications, implement Mutual TLS with Spring Security:

@Configuration
@EnableWebSecurity
public class MutualTlsSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .requiresChannel()
                .anyRequest()
                .requiresSecure()
                .and()
            .x509()
                .subjectPrincipalRegex("CN=(.*?)(?:,|$)"))
                .and()
            .authorizeHttpRequests()
                .requestMatchers("/api/public/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .requestMatchers("/api/user/**").hasAnyRole("USER", "ADMIN")
                .anyRequest().authenticated();
        
        return http.build();
    }
    
    @Bean
    public X509AuthenticationProvider x509AuthenticationProvider() {
        return new X509AuthenticationProvider();
    }
    
    @Bean
    public AuthenticationManager authenticationManager(
            X509AuthenticationProvider x509Provider) {
        return new AuthenticationManager(x509Provider);
    }
}

@Component
public class X509AuthenticationProvider implements AuthenticationProvider {
    
    @Override
    public Authentication authenticate(Authentication authentication) 
            throws AuthenticationException {
        
        X509Certificate clientCert = 
            (X509Certificate) authentication.getCredentials();
        
        // Verify certificate chain and revocation
        if (!verifyCertificate(clientCert)) {
            throw new BadCredentialsException("Invalid certificate");
        }
        
        // Extract identity and roles from certificate
        String subject = clientCert.getSubjectX500Principal().getName();
        String[] parts = subject.split(",");
        
        Map attributes = new HashMap<>();
        for (String part : parts) {
            String[] kv = part.split("=");
            if (kv.length == 2) {
                attributes.put(kv[0].trim(), kv[1].trim());
            }
        }
        
        String username = attributes.getOrDefault("CN", "unknown");
        String role = determineRoleFromCertificate(clientCert);
        
        // Create authentication token with roles
        return new UsernamePasswordAuthenticationToken(
            username, clientCert, 
            AuthorityUtils.createAuthorityList("ROLE_" + role)
        );
    }
    
    private boolean verifyCertificate(X509Certificate cert) {
        // Implement certificate verification
        // Check CA signature, revocation, validity period
        return true;
    }
    
    private String determineRoleFromCertificate(X509Certificate cert) {
        // Application-specific logic to determine role
        // Could be based on organization, custom extensions, etc.
        return "USER";
    }
}

The key remediation principles are:

  1. Never rely solely on certificate presence for authorization
  2. Always verify certificate chain and revocation status
  3. Map certificates to identities using multiple properties, not just CN
  4. Implement proper role-based access control
  5. Log and monitor authentication and authorization decisions

Testing your remediation is critical. Use middleBrick's continuous monitoring to ensure your fixes are effective:

# Continuous monitoring configuration
{
  "apis": [
    {
      "url": "https://api.example.com",
      "scan_frequency": "daily",
      "fail_threshold": "B",
      "alert_channels": ["email", "slack"]
    }
  ]
}

Frequently Asked Questions

How is Broken Access Control different in Mutual TLS versus basic TLS?
In Mutual TLS, the vulnerability often stems from assuming that client certificate authentication equals authorization. While basic TLS might have broken access control due to weak passwords or session management, Mutual TLS vulnerabilities typically involve improper certificate validation, missing revocation checks, or failing to map certificate properties to specific permissions. The mutual authentication creates a false sense of security that all clients with valid certificates should have access.
Can middleBrick detect Mutual TLS-specific Broken Access Control issues?
Yes, middleBrick specifically tests Mutual TLS endpoints by attempting to access protected resources with different certificate configurations. It checks if endpoints properly validate client certificates, verify revocation status, and enforce role-based access control. The scanner tests both authenticated and unauthenticated access attempts to identify authorization bypasses that are specific to Mutual TLS implementations.