HIGH rainbow table attackadonisjsmutual tls

Rainbow Table Attack in Adonisjs with Mutual Tls

Rainbow Table Attack in Adonisjs with Mutual Tls — how this specific combination creates or exposes the vulnerability

A rainbow table attack leverages precomputed hash chains to reverse cryptographic hashes, commonly targeting password storage. In Adonisjs, if password fields are hashed with a weak or unsalted algorithm, an attacker who obtains the hash database can use a rainbow table to map hashes back to plaintext passwords. This risk exists regardless of transport security, but combining it with Mutual TLS (mTLS) introduces a nuanced interaction: mTLS ensures that only clients with a valid certificate can reach the application endpoint, which may give a false sense of overall security.

When mTLS is used for client authentication at the transport layer, developers might assume that backend-to-database or service-to-service channels are fully protected and therefore neglect strong password hashing practices in Adonisjs. However, mTLS does not protect application-layer data once a request is processed. If an Adonisjs app stores passwords using unsalted SHA-1 or MD5, an attacker who compromises the database (e.g., via SQL injection, backup exposure, or insider access) can build or use a rainbow table to recover passwords. The presence of mTLS does not mitigate weak hashing; it only authenticates clients to the server, not the integrity of stored credentials.

Consider an Adonisjs route that authenticates a user over mTLS and then compares a submitted password hash against a database value:

// routes.ts (Adonisjs) - simplified example
Route.post('login', async ({ request, auth }) => {
  const { username, password } = request.body()
  const user = await User.findBy('username', username)
  // WARNING: unsalted fast hash comparison
  if (hash(password) === user.password_hash) {
    await auth.use('api').login(user)
  }
})

In this pattern, if hash is a fast, unsalted algorithm and the database is exposed, an attacker can generate rainbow tables offline for common passwords and match them against user.password_hash. mTLS ensures only certificate-holding clients can invoke the endpoint, but it does not prevent database compromise or protect stored hashes. The attack surface therefore splits: transport security (mTLS) is strong, while credential storage (application layer) remains weak. This misalignment can lead to account takeover even when mTLS is enforced.

Additionally, if an Adonisjs application exposes an API that returns password hashes or password-derived values (e.g., for legacy integration), the combination of mTLS and a data exfiltration path can aid an attacker in harvesting hashes to build or use rainbow tables. mTLS limits who can connect, but once authenticated, the application’s handling of hashes dictates whether stolen data is useful for offline cracking.

Mutual Tls-Specific Remediation in Adonisjs — concrete code fixes

Remediation focuses on two layers: ensuring mTLS is correctly configured to authenticate clients, and strengthening credential storage so that stolen hashes cannot be trivially reversed. The following examples show how to enforce mTLS in Adonisjs and adopt strong password hashing.

Enforce Mutual TLS in Adonisjs

Adonisjs does not manage TLS directly; TLS termination typically occurs at a reverse proxy or load balancer (e.g., Nginx, Traefik). The application should validate that the client certificate is present and trusted. Below is an Adonisjs request hook that checks for a client certificate on sensitive routes:

// start/hooks.ts
import { Exception } from '@poppinss/utils'

export const requireClientCert = async (ctx, next) => {
  const clientCert = ctx.request.socket.getPeerCertificate()
  if (!clientCert || Object.keys(clientCert).length === 0) {
    throw new Exception('Client certificate required', 401, 'E_MTLS_REQUIRED')
  }
  // Optionally validate certificate fields (subject, issuer, fingerprint)
  const fingerprint = clientCert.fingerprint
  const allowedFingerprints = new Set([
    'AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD'
  ])
  if (!allowedFingerprints.has(fingerprint)) {
    throw new Exception('Certificate not authorized', 403, 'E_CERT_NOT_AUTHORIZED')
  }
  await next()
}

Then apply this hook to routes that require mTLS:

// routes.ts
import Route from '@ioc:Adonis/Core/Route'
import { requireClientCert } from 'App/Start/hooks'

Route.group(() => {
  Route.post('login', async ({ request, auth }) => {
    const { username, password } = request.body()
    const user = await User.findBy('username', username)
    if (user && await verifyPassword(password, user.password_hash)) {
      await auth.use('api').login(user)
    }
  }).middleware([requireClientCert])
}).prefix('v1')

Secure Password Storage in Adonisjs

Use a strong adaptive hashing algorithm with a unique salt per user. Adonisjs integrates with Argon2 and bcrypt via the built-in hash provider. Configure and use it as follows:

// config/hash.ts
export default {
  default: 'argon2',
  config: {
    argon2: {
      type: 'argon2id',
      memoryCost: 19456,  // 19 MB
      timeCost: 2,
      parallelism: 1
    },
    bcrypt: {
      rounds: 12
    }
  }
}

In your User model or service, hash and verify using the provider:

import { Hash } from '@ioc:Adonis/Core/Hash'

// When creating or updating a password
const hashed = await Hash.make(plainPassword)

// When verifying during login
const verified = await Hash.verify(existingHash, plainPassword)

Combining mTLS enforcement with strong password hashing ensures that even if hashes are leaked, offline cracking via rainbow tables remains impractical. mTLS reduces the set of potential clients, but robust hashing protects stored credentials independently.

Frequently Asked Questions

Does mTLS prevent rainbow table attacks on stored passwords in Adonisjs?
No. Mutual TLS secures transport and client authentication but does not protect stored password hashes. Weak hashing remains vulnerable to offline rainbow table attacks regardless of mTLS.
What hashing configuration is sufficient to resist rainbow tables in Adonisjs?
Use adaptive, salted algorithms such as Argon2id or bcrypt with appropriate cost parameters. Avoid fast unsalted hashes like MD5 or SHA-1 for password storage.