HIGH bleichenbacher attackfeathersjscockroachdb

Bleichenbacher Attack in Feathersjs with Cockroachdb

Bleichenbacher Attack in Feathersjs with Cockroachdb — how this specific combination creates or exposes the vulnerability

A Bleichenbacher attack is a chosen-ciphertext attack against asymmetric encryption schemes that use PKCS#1 v1.5 padding and error messages that reveal whether a decrypted value is valid. In a FeathersJS application backed by CockroachDB, the risk arises when the service performs decryption of data (e.g., API keys, tokens, or PII) using RSA with PKCS#1 v1.5 before validating ownership or access control. If an attacker can submit many ciphertexts and observe distinct timing differences or explicit error responses (e.g., invalid padding vs. invalid signature), they can iteratively decrypt or forge valid ciphertexts without possessing the private key.

FeathersJS services often expose REST or socket endpoints that accept encrypted payloads. When a parameter such as encrypted_token is passed, and the backend decrypts it using a private key stored in the application layer, the service may query CockroachDB to retrieve the associated user or scope. If the decryption step is performed before proper authentication and if the error handling distinguishes between malformed ciphertext and valid-but-unauthorized data, the service leaks information through timing or status codes. CockroachDB itself does not introduce the vulnerability, but its use as the authoritative data store means that each decryption attempt may trigger database lookups (e.g., SELECT * FROM users WHERE api_key = $1), and subtle timing differences in query responses or application-level conditionals can amplify the attack surface.

Consider a FeathersJS hook that decrypts a JWE before attaching the user to the request. If the decryption uses RSA-OAEP incorrectly configured or falls back to PKCS#1 v1.5, and the service returns different HTTP status codes or response times for invalid padding versus decryption success, an attacker can mount a Bleichenbacher attack. The attacker crafts many ciphertexts, observes responses, and gradually recovers the plaintext. If the decrypted value contains a user identifier used in a subsequent CockroachDB query, the attacker may also exploit Insecure Direct Object Reference (IDOR) patterns to escalate impact. This combination of weak cryptographic practices in FeathersJS and data-centric validation in CockroachDB queries creates a practical path for unauthorized data access.

Real-world analogies include CVE-2017-13097 (affecting devices using PKCS#1 v1.5 in TLS) and practical breaks against RSA PKCS#1 v1.5 in TLS implementations. In the FeathersJS + CockroachDB context, the issue is not Cockroachdb-specific cryptography but the service-side handling of decryption errors and database interactions. A typical vulnerable pattern is a FeathersJS service that does not use constant-time comparison and exposes whether a decryption succeeded before verifying authentication, enabling adaptive chosen-ciphertext queries.

Cockroachdb-Specific Remediation in Feathersjs — concrete code fixes

Remediation focuses on ensuring decryption never reveals distinguishable errors, enforcing strict authentication before any cryptographic operations, and using constant-time patterns when interacting with CockroachDB. Avoid decrypting user-controlled data with RSA PKCS#1 v1.5; prefer RSA-OAEP with SHA-256 or AEAD schemes such as AES-GCM. In FeathersJS, move authentication and authorization checks before any decryption attempt, and ensure that all database queries use parameterized statements to prevent SQL injection side channels.

Below is a secure FeathersJS service example using the official CockroachDB Node.js driver. The service validates a JWT access token before performing any decryption or database query, uses constant-time comparison for sensitive identifiers, and ensures errors are uniform.

const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const { Sequelize } = require('sequelize');
const { Client } = require('pg'); // CockroachDB wire-compatible driver
const jwt = require('jsonwebtoken');
const crypto = require('crypto');

const app = feathers();
const sequelize = new Sequelize({
  dialect: 'postgres',
  host: 'your-cockroachdb-host',
  port: 26257,
  database: 'yourdb',
  username: 'youruser',
  password: 'yourpassword',
  logging: false
});

// Define a User model that maps to a CockroachDB table
const User = sequelize.define('user', {
  id: {
    type: Sequelize.UUID,
    defaultValue: Sequelize.UUIDV4,
    primaryKey: true
  },
  apiKeyHash: {
    type: Sequelize.STRING,
    allowNull: false
  }
}, {
  timestamps: false,
  tableName: 'users'
});

// Constant-time comparison helper to avoid timing leaks
function safeCompare(a, b) {
  return crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b));
}

app.configure(express.rest());

app.use('/secure', {
  async before(context) {
    const { authorization } = context.params.query;
    if (!authorization || !authorization.startsWith('Bearer ')) {
      throw new Error('Unauthorized');
    }
    const token = authorization.slice(7);
    let payload;
    try {
      // Validate and verify JWT before any DB access
      payload = jwt.verify(token, process.env.JWT_PUBLIC_KEY, { algorithms: ['RS256'] });
    } catch (err) {
      throw new Error('Unauthorized');
    }

    // Fetch user using parameterized query; CockroachDB driver supports prepared statements
    const user = await User.findOne({
      where: { id: payload.sub }
    });
    if (!user) {
      throw new Error('Unauthorized');
    }

    // Attach user in constant-time safe manner for downstream use
    context.params.user = user;
  },

  async after(hook) {
    // Ensure no sensitive data leaks in responses
    if (hook.result && hook.result.apiKeyHash) {
      delete hook.result.apiKeyHash;
    }
    return hook;
  }
});

// Example secure endpoint that does not perform RSA decryption on client input
app.service('/secure/profile').hooks({
  before: {
    async get(context) {
      const user = context.params.user;
      if (!user) {
        throw new Error('Forbidden');
      }
      // Use CockroachDB row-level security or application-level checks
      context.result = { profile: 'safe-data', userId: user.id };
    }
  }
});

(async () => {
  await sequelize.authenticate();
  console.log('Connection established with CockroachDB.');
  await app.listen(3030);
})();

Key remediation practices:

  • Never decrypt with RSA PKCS#1 v1.5 in server-side logic; use RSA-OAEP or switch to symmetric encryption (AES-GCM) where appropriate.
  • Perform authentication and ownership checks before any cryptographic operation or database query to avoid timing leaks.
  • Use parameterized queries with the CockroachDB driver to prevent SQL injection that could aid secondary attacks.
  • Return uniform error messages and status codes (e.g., 401 Unauthorized) regardless of whether the failure is due to invalid token, malformed ciphertext, or missing row.
  • Enable CockroachDB’s prepared statements and ensure TLS is enforced for database connections.

Frequently Asked Questions

Can a Bleichenbacher attack be performed against a FeathersJS API that uses CockroachDB without any encryption?
No. The attack requires an asymmetric decryption oracle. If your FeathersJS service does not perform RSA decryption or does not expose distinguishable error behaviors, a Bleichenbacher attack is not feasible regardless of CockroachDB usage.
Does middleBrick detect Bleichenbacher-related misconfigurations in FeathersJS services backed by CockroachDB?
Yes. middleBrick scans unauthenticated attack surfaces and includes checks for improper error handling and cryptographic misuse. Its findings map to relevant OWASP API Top 10 categories and provide remediation guidance, though it does not fix or block issues.