HIGH side channel attackadonisjsmutual tls

Side Channel Attack in Adonisjs with Mutual Tls

Side Channel Attack in Adonisjs with Mutual Tls

A side channel attack in AdonisJS with mutual TLS (mTLS) occurs when an attacker infers sensitive information from observable behavior of the mTLS handshake or encrypted request processing, rather than breaking encryption. While mTLS strengthens authentication by requiring both server and client certificates, it does not prevent timing, error, or resource-based side channels that leak information about certificate validity, user identity, or business logic.

In AdonisJS, which runs on Node.js, side channels can emerge at the integration layer between the TLS termination (often handled by a reverse proxy like NGINX or a load balancer) and the application’s route handling. For example, the framework may perform certificate verification steps—validating the client certificate chain, checking revocation via CRL/OCSP, and mapping the certificate to a user or role—before the request reaches application code. If these steps are implemented in application code rather than at the edge, their execution time or error responses may vary based on certificate properties, introducing measurable differences an attacker can observe.

Consider an endpoint that retrieves user profiles. With mTLS, the client presents a certificate containing a subject or serial number that maps to a user. If AdonisJS performs a synchronous lookup (e.g., querying a database or cache) to validate the certificate and fetch user data before allowing access, the response time will differ for valid versus invalid certificates. An attacker can measure round-trip times to infer whether a given certificate is recognized, effectively conducting a timing side channel. Similarly, distinct error messages—such as “certificate not found” versus “invalid signature”—reveal the stage at which validation failed, aiding an attacker in narrowing down viable certificates.

Another vector involves resource usage during TLS session resumption. AdonisJS applications behind mTLS may handle session tickets or session IDs differently depending on whether a client certificate is presented. If session reuse behaves differently—e.g., skipping certain validation steps for resumed sessions—an attacker can detect patterns by observing connection setup times. This is especially relevant when using HTTP/2 with mTLS, where connection state and flow control can expose variations in processing overhead.

Error handling in AdonisJS further amplifies risk. Uncaught exceptions during certificate validation, such as failures in parsing or chain verification, may return stack traces or specific messages that do not occur under normal operation. These messages can reveal whether the failure occurred during parsing, chain building, or policy evaluation. Even logging practices can contribute: verbose logs that include certificate subject details can be correlated with application metrics to infer which certificates trigger deeper inspection.

To assess such risks, tools like middleBrick can scan an AdonisJS endpoint protected by mTLS. While the scanner tests unauthenticated attack surfaces, it can detect timing inconsistencies and error behavior that suggest side channel exposure when combined with mTLS configurations. Its LLM/AI security checks, including active prompt injection probes and output scanning, are designed to uncover unique risks in AI-integrated endpoints, though for mTLS-protected APIs, the focus remains on observable behavioral differences in authentication and validation flows.

Mutual Tls-Specific Remediation in Adonisjs

Remediation focuses on removing timing and information leaks in the validation flow and standardizing responses. In AdonisJS, perform certificate validation at the edge or via a dedicated proxy rather than in application code. If validation must occur in AdonisJS, ensure all certificate checks run in constant time and return uniform error messages. Avoid branching logic that changes processing time based on certificate properties.

Use environment-driven configuration for TLS options and keep certificate revocation checks efficient, possibly caching results to reduce variable latency. Log minimally and avoid including certificate details in responses or logs that could aid an attacker. Below are concrete code examples for integrating mTLS in AdonisJS with consistent error handling.

Example 1: Basic mTLS Setup with Fixed Response

This example shows configuring an HTTPS server in AdonisJS with strict mTLS, returning a generic error for any TLS failure.

const { Ignitor } = require('@adonisjs/ignitor')
const fs = require('fs')

new Ignitor(require('@adonisjs/fold'))
  .httpServer()
  .startServer({
    key: fs.readFileSync('ssl/server.key'),
    cert: fs.readFileSync('ssl/server.crt'),
    ca: fs.readFileSync('ssl/ca.crt'),
    requestCert: true,
    rejectUnauthorized: true,
  }, (error, request, response) => {
    // Always return a generic error to prevent information leakage
    response.writeHead(403, { 'Content-Type': 'text/plain' })
    response.end('Access denied')
  })

Example 2: Middleware-Based Validation with Constant-Time Checks

Use middleware to inspect the client certificate after the TLS handshake. Ensure the lookup logic does not depend on certificate values in a way that affects timing.

const crypto = require('crypto')

class MTLSCertCheck {
  async handle({ request }, next) {
    const cert = request.socket.getPeerCertificate()
    if (!cert || !cert.subject) {
      return response.unauthorized('Invalid certificate')
    }

    // Simulate constant-time validation: perform a dummy hash to mask timing
    const dummy = crypto.createHash('sha256').update('dummy').digest()

    // Map certificate to user in a way that does not leak via timing
    const user = await this.getUserByCertHash(cert.thumbprint)
    if (!user) {
      return response.unauthorized('Invalid certificate')
    }

    request.user = user
    await next()
  }

  async getUserByCertHash(thumbprint) {
    // Assume a constant-time cache or DB lookup implementation
    return cache.get(`cert:${thumbprint}`)
  }
}
module.exports = MTLSCertCheck

Example 3: Proxy Offloading mTLS

Offload mTLS to a reverse proxy (e.g., NGINX) so AdonisJS only sees requests with valid client certificates. This removes the need for in-app TLS logic and side-channel-prone validation code.

# NGINX configuration snippet
server {
    listen 443 ssl;
    ssl_certificate /etc/ssl/certs/server.crt;
    ssl_certificate_key /etc/ssl/private/server.key;
    ssl_client_certificate /etc/ssl/certs/ca.crt;
    ssl_verify_client on;

    location / {
        proxy_pass http://localhost:3333;
        proxy_set_header X-SSL-Cert-Digest "$ssl_client_escaped_cert";
    }
}

With this setup, AdonisJS receives requests only after successful mTLS at the proxy, reducing in-process side channels. Combine this with middleBrick’s continuous monitoring via the Pro plan to detect timing anomalies and configuration issues over time.

Frequently Asked Questions

Can mTLS in AdonisJS still leak information through error messages?
Yes, if error messages differ between certificate validation failures. Use uniform responses and perform validation at the edge to prevent this.
Does middleBrick test for side channel risks in mTLS-protected endpoints?
middleBrick detects timing and behavior anomalies during scans. Its LLM/AI security checks are useful for endpoints that also integrate AI components, but side channel risks primarily depend on observable server behavior.