Brute Force Attack in Adonisjs with Cockroachdb
Brute Force Attack in Adonisjs with Cockroachdb — how this specific combination creates or exposes the vulnerability
A brute force attack against an AdonisJS application using CockroachDB typically targets authentication endpoints where usernames and passwords are verified. Because AdonisJS does not enforce account lockouts or progressive delays by default, an attacker can send many password guesses without server-side throttling. When the app queries CockroachDB, each attempt performs a SQL lookup on the users table. If indexes are not aligned with the query shape or if error messages differ between missing users and incorrect passwords, an attacker can use timing differences or enumeration feedback to infer valid usernames.
In this stack, the interaction between AdonisJS ORM (Lucid) and CockroachDB can inadvertently expose behavior that aids brute force attempts. For example, if the application returns distinct errors for "user not found" versus "password incorrect," an attacker learns whether a username exists. CockroachDB’s strong consistency and distributed nature do not mitigate application-level logic flaws; queries like SELECT * FROM users WHERE email = $1 will return a row or not, and the app’s response determines what information is disclosed. Without rate limiting, an unauthenticated attack surface remains open, and the 5–15 second scan window of middleBrick can detect missing controls by probing login endpoints.
Additionally, if session management or token issuance does not bind tightly to a single origin or if password reset tokens are predictable, brute force or token guessing may extend beyond authentication. middleBrick’s checks for Authentication, Rate Limiting, and Input Validation highlight these issues by testing the unauthenticated attack surface. Findings align with OWASP API Top 10 and common compliance frameworks, emphasizing the need for robust controls rather than relying on database infrastructure alone.
Cockroachdb-Specific Remediation in Adonisjs — concrete code fixes
Remediation requires changes in AdonisJS application logic and database interaction patterns. Use constant-time comparison for credentials and ensure uniform responses to prevent username enumeration. Implement rate limiting at the API route level and enforce strong password policies. The following CockroachDB and AdonisJS code examples illustrate secure patterns.
1. Parameterized query with consistent error handling
Always use parameterized queries to avoid injection and keep behavior predictable. Return a generic error message regardless of whether the user exists.
import { BaseModel } from '@ioc:Adonis/Lucid/Orm'
export default class User extends BaseModel {
public static async verifyCredentials(email: string, password: string): Promise<{ user: any; error: string | null }> {
const user = await this.query()
.where('email', email)
.limit(1)
.select('*')
.execute()
.then(res => res.rows[0])
.catch(() => null)
if (!user) {
// Simulate password check to keep timing similar
await this.dummyPasswordCheck(password)
return { user: null, error: 'Invalid credentials' }
}
const isValid = await verifyPassword(password, user.password_hash)
return { user: isValid ? user : null, error: isValid ? null : 'Invalid credentials' }
}
private static async dummyPasswordCheck(password: string): Promise<void> {
// Use a hash computation that takes comparable time to real password check
await import('bcrypt').then(bcrypt => bcrypt.hash(password, 10)).catch(() => {/* ignore */})
}
}
2. Rate limiting via middleware on authentication routes
Apply a rate limiter to login and password reset endpoints to restrict attempts per identifier or IP.
import { middleware } from '@ioc:Adonis/Core/Middleware'
import { RateLimiter } from '@ioc:Adonis/Addons/RateLimiter'
export const authRateLimiter = middleware(async (ctx, next) => {
const identifier = ctx.request.input('email') || ctx.request.ip()
const allowed = await RateLimiter.check(`auth:${identifier}`, 5, 'minute')
if (!allowed) {
ctx.response.status(429).send({ error: 'Too many attempts, try again later.' })
return
}
await next()
})
// In routes.ts
Route.post('login', 'AuthController.login').middleware([authRateLimiter])
Route.post('password-reset', 'AuthController.passwordReset').middleware([authRateLimiter])
3. CockroachDB schema considerations
Ensure your users table supports efficient, index-backed lookups and stores password hashes securely. Use UUID primary keys to avoid predictable IDs, and keep sensitive columns protected.
-- CockroachDB SQL schema
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email STRING NOT NULL UNIQUE,
password_hash STRING NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
last_login TIMESTAMPTZ NULL
);
-- Index to support fast email lookup
CREATE INDEX idx_users_email ON users (email);
4. Enforce password policies and MFA where possible
Use AdonisJS hooks to validate password strength and consider integrating multi-factor authentication to reduce the impact of credential guessing.
import { schema } from '@ioc:Adonis/Core/Validator'
const passwordPolicy = schema.object({
password: schema.string({}, [rules.minLength(12), rules.confirmed(), rules.strongPassword()])
})
export const passwordResetSchema = schema.object({
email: schema.string({}, [rules.email(), rules.exists({ table: 'users', column: 'email' })]),
token: schema.string({}, [rules.minLength(6), rules.maxLength(6)]),
password: passwordPolicy
})