Dns Cache Poisoning in Cassandra
How DNS Cache Poisoning Manifests in Cassandra
When a Cassandra client or driver resolves a contact point via DNS, an attacker who has poisoned the resolver can return an IP address under their control. The driver then opens a connection to the malicious node, believing it to be a legitimate Cassandra instance. This gives the attacker the ability to:
- Intercept or modify CQL queries and responses.
- Harvest authentication credentials if the client sends them before TLS is established.
- Inject malicious queries that read or write data.
Specific code paths where this can occur include:
- DataStax Java driver: The
DefaultEndpointResolvercallsInetAddress.getByName(host)for each contact point. If the DNS response is poisoned, the driver receives a malicious IP and proceeds with the normal connection handshake. - Cassandra seed provider: The
SimpleSeedProvider(configured incassandra.yaml) also resolves seed node hostnames via DNS at startup. Poisoned seeds can cause a node to join an attacker‑controlled cluster. - Client‑side load‑balancing policies: Policies such as
DCAwareRoundRobinPolicyrepeatedly resolve hostnames to balance traffic, providing multiple opportunities for a poisoned response to be used.
Because the Cassandra native protocol (port 9042) and Thrift interface (port 9160) are binary, the attack does not require an HTTP layer; any component that performs a DNS lookup for a Cassandra endpoint is a potential vector.
Cassandra‑Specific Detection
middleBrick does not perform DNS resolution itself, but it can expose the symptoms of a DNS cache poisoning risk by scanning the API surface that Cassandra presents to clients. When a Cassandra node exposes its native protocol, Thrift, or an HTTP/gRPC wrapper (e.g., DataStax Astra DB HTTP API) without proper protections, middleBrick’s checks will flag the issue:
- Authentication check: Detects whether the endpoint accepts connections without valid credentials. An unauthenticated Cassandra node is a prerequisite for an attacker who has redirected traffic via DNS poisoning.
- Encryption check: Reports if client‑to‑node or node‑to‑node TLS is disabled. Clear‑text traffic makes it trivial for an attacker who controls the redirected node to sniff or modify CQL frames.
- Data Exposure check: Looks for version strings, schema information, or debug endpoints leaked before authentication. Such leakage can help an attacker confirm they have reached a Cassandra node after a DNS redirect.
- Rate Limiting and Input Validation checks: While not directly related to DNS poisoning, they help identify additional weaknesses that could be chained with a redirected connection.
Example detection workflow:
- Identify the host(s) used as Cassandra contact points in your application (e.g.,
cassandra-cluster.example.com). - Run a middleBrick scan against any HTTP/gRPC interface exposed on those hosts (if present):
middlebrick scan https://cassandra-cluster.example.com:8080/api/v1/schema - If no HTTP interface exists, you can still infer risk by scanning the native port with a tool that middleBrick can invoke via its CLI (the CLI accepts a URL; for TCP‑only services you would need to wrap them in an HTTP proxy for testing). The key is that middleBrick will report missing authentication or encryption, which are the core mitigations against a DNS‑poisoning‑based attack.
- Review the finding details: middleBrick will provide severity, remediation guidance, and a mapping to OWASP API Security Top 10 (e.g., A2: Broken Authentication, A3: Excessive Data Exposure).
By catching missing authentication or encryption, middleBrick highlights the exact conditions that an attacker would exploit after successfully poisoning a DNS resolver.
Cassandra‑Specific Remediation
Mitigating DNS cache poisoning in a Cassandra deployment involves both network‑level controls and Cassandra configuration changes that ensure clients only talk to trusted nodes, even if DNS returns a malicious address.
Network‑level defenses
- Enable DNSSEC on recursive resolvers used by application hosts and Cassandra nodes to prevent spoofed responses.
- Restrict outbound DNS queries to only trusted resolvers using firewall rules.
- Where possible, replace DNS‑based contact points with static IP addresses in client configuration.
Cassandra configuration
Edit cassandra.yaml to enforce authentication and encryption:
# Enable password‑based authentication
authenticator: PasswordAuthenticator
authorizer: CassandraAuthorizer
# Client‑to‑node encryption
client_encryption_options:
enabled: true
keystore: /etc/cassandra/conf/.keystore
keystore_password: cassandra
truststore: /etc/cassandra/conf/.truststore
truststore_password: cassandra
require_client_auth: true
# Optional: node‑to‑node encryption (recommended for multi‑DC clusters)
internode_encryption: all
server_encryption_options:
enabled: true
keystore: /etc/cassandra/conf/.keystore
keystore_password: cassandra
truststore: /etc/cassandra/conf/.truststore
truststore_password: cassandra
require_client_auth: true
Application‑side driver hardening
When using the DataStax Java driver, avoid relying solely on DNS for contact points and enforce TLS and credentials:
import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.core.config.DriverConfigLoader;
import com.datastax.oss.driver.api.core.ssl.DefaultSslEngineFactory;
import java.net.InetSocketAddress;
import java.nio.file.Paths;
public class CassandraClient {
public static CqlSession buildSession() {
return CqlSession.builder()
// Add contact points as raw IPs to bypass DNS lookup
.addContactPoint(new InetSocketAddress("203.0.113.10", 9042))
.addContactPoint(new InetSocketAddress("203.0.113.11", 9042))
// Enforce TLS
.withSslEngineFactory(new DefaultSslEngineFactory(
Paths.get("/path/to/truststore.jks"),
"changeit".toCharArray()))
// Authenticate
.withAuthCredentials("app_user", "StrongPassw0rd!")
.build();
}
}
If you must keep hostnames, enable the driver’s resolve-contact-points option to cache resolved IPs for the lifetime of the session, reducing the window for a poisoned response to be used:
CqlSession.builder()
.addContactPoint("cassandra01.example.com")
.withResolveContactPoints(true) // resolves once, then uses cached IP
.build();
Finally, monitor logs for unexpected connection attempts. Cassandra logs the IP address of each incoming connection; a sudden appearance of addresses outside your expected ranges can indicate a DNS‑based redirection.