Skip to content

Enforce hostname verification by default for TLS connections#4495

Merged
ggivo merged 5 commits into
masterfrom
topic/ggivo/tls-enforce-full-certificate-validation
Apr 24, 2026
Merged

Enforce hostname verification by default for TLS connections#4495
ggivo merged 5 commits into
masterfrom
topic/ggivo/tls-enforce-full-certificate-validation

Conversation

@ggivo

@ggivo ggivo commented Apr 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes hostname verification bypass when using simple TLS configuration (ssl=true)
and deprecates the low-level SSL configuration methods in favor of SslOptions.

Changes

  • Security fix: Enable HTTPS endpoint identification algorithm by default in
    DefaultJedisSocketFactory
  • Deprecation: Mark JedisClientConfig.getSslSocketFactory() /
    getSslParameters() and builder setters ssl(boolean) / sslSocketFactory(...) /
    sslParameters(...) as @Deprecated since 7.4.2 in favor of SslOptions.
    isSsl() remains as the query method for "is TLS enabled?".
  • New: SslOptions.defaults() factory for a clean migration from ssl(true)
  • Docs: Refresh Javadoc on JedisClientConfig (interface-contract style) and
    SslOptions (verification modes, truststore examples)
  • Test coverage: Add hostname verification tests for all client types (Jedis,
    RedisClient, RedisClusterClient, RedisSentinelClient)

Behavior change

Before: ssl(true) accepted any certificate without hostname verification
After: ssl(true) enforces hostname verification by default

Migration

Recommended: switch to SslOptions

For TLS with JVM defaults (truststore, full verification):

// Before (deprecated)
JedisClientConfig config = DefaultJedisClientConfig.builder()
    .ssl(true)
    .password("foobared")
    .build();

// After
JedisClientConfig config = DefaultJedisClientConfig.builder()
    .sslOptions(SslOptions.defaults())
    .password("foobared")
    .build();

For custom truststores, mutual TLS, or other TLS options use SslOptions.builder()
(see SslOptions Javadoc for examples).

Fallback to previous behaviour (hostname verification disabled)

Preferred: use SslOptions with SslVerifyMode.CA

Validates the certificate chain but skips hostname verification. Use this when
connecting via IP or a name not listed in the certificate's SAN/CN:

SslOptions sslOptions = SslOptions.builder()
    .sslVerifyMode(SslVerifyMode.CA)
    .build();

JedisClientConfig config = DefaultJedisClientConfig.builder()
    .sslOptions(sslOptions)
    .password("foobared")
    .build();

Alternative: override with custom SSLParameters (deprecated path)

SSLParameters sslParams = new SSLParameters();
// Do NOT set endpoint identification algorithm

JedisClientConfig config = DefaultJedisClientConfig.builder()
    .ssl(true)
    .sslParameters(sslParams)
    .password("foobared")
    .build();

Note: Both options disable hostname verification. Prefer SslVerifyMode.CA
over custom SSLParameters — it is more explicit, still verifies the certificate
chain, and leaves other SSLParameters defaults untouched. Only use in trusted
environments.

Fixes

  • CAE-2794: [Jedis] Jedis skips hostname verification when simple TLS configuration is provided

Note

High Risk
Changes TLS connection defaults to enable hostname verification, which is security-sensitive and can break existing deployments that connect via IP/incorrect hostnames. Also introduces deprecations and new test endpoints that may affect downstream builds relying on previous legacy SSL behavior.

Overview
Enforces secure-by-default TLS by enabling HTTPS hostname verification on TLS sockets when using the legacy ssl(true) path (i.e., when no SslOptions/custom SSLParameters are provided), preventing hostname-verification bypasses.

Deprecates legacy SSL knobs (JedisClientConfig#getSslSocketFactory(), getSslParameters(), and DefaultJedisClientConfig.Builder setters ssl(...), sslSocketFactory(...), sslParameters(...)) in favor of SslOptions, and adds SslOptions.defaults() plus expanded Javadoc to guide migration.

Adds integration coverage and fixtures for hostname verification across Jedis, RedisClient, RedisClusterClient, and RedisSentinelClient, including new “wrong host” endpoints/config to assert failures by default and success when explicitly disabling endpoint identification via custom SSLParameters.

Reviewed by Cursor Bugbot for commit 8c2c3ac. Bugbot is set up for automated code reviews on this repo. Configure here.

Enable HTTPS endpoint identification algorithm by default in DefaultJedisSocketFactory
when ssl(true) is used without custom SSLParameters.
Add tests (Jedis, RedisClient, RedisClusterClient, RedisSentinelClient) to
verify hostname verification failure when certificate CN/SAN doesn't match the
connection hostname.

Users can still override by providing custom SSLParameters.

Fixes: CAE-2794
@jit-ci

jit-ci Bot commented Apr 23, 2026

Copy link
Copy Markdown

🛡️ Jit Security Scan Results

CRITICAL HIGH MEDIUM

✅ No security findings were detected in this PR


Security scan by Jit

@github-actions

github-actions Bot commented Apr 23, 2026

Copy link
Copy Markdown

Test Results

  191 files  ±0    191 suites  ±0   11m 37s ⏱️ +18s
9 223 tests +2  8 759 ✅  - 406  464 💤 +408  0 ❌ ±0 
3 457 runs   - 4  3 306 ✅  - 150  151 💤 +146  0 ❌ ±0 

Results for commit 8c2c3ac. ± Comparison against base commit fa219c3.

This pull request removes 7 and adds 9 tests. Note that renamed tests count towards both.
redis.clients.jedis.commands.unified.search.FTHybridCommandsTestBase$SupportedScorersTest ‑ testScorer(Scorer, double, double)[1]
redis.clients.jedis.commands.unified.search.FTHybridCommandsTestBase$SupportedScorersTest ‑ testScorer(Scorer, double, double)[2]
redis.clients.jedis.commands.unified.search.FTHybridCommandsTestBase$SupportedScorersTest ‑ testScorer(Scorer, double, double)[3]
redis.clients.jedis.commands.unified.search.FTHybridCommandsTestBase$SupportedScorersTest ‑ testScorer(Scorer, double, double)[4]
redis.clients.jedis.commands.unified.search.FTHybridCommandsTestBase$SupportedScorersTest ‑ testScorer(Scorer, double, double)[5]
redis.clients.jedis.commands.unified.search.FTHybridCommandsTestBase$SupportedScorersTest ‑ testScorer(Scorer, double, double)[6]
redis.clients.jedis.commands.unified.search.FTHybridCommandsTestBase$SupportedScorersTest ‑ testScorer(Scorer, double, double)[7]
redis.clients.jedis.commands.unified.search.FTHybridCommandsTestBase$SupportedScorersTest ‑ testScorer(Scorer, double, double)
redis.clients.jedis.tls.JedisIT ‑ connectWrongHost
redis.clients.jedis.tls.JedisIT ‑ connectWrongHostWithSslParameters
redis.clients.jedis.tls.RedisClientIT ‑ connectWithWrongHost
redis.clients.jedis.tls.RedisClientIT ‑ connectWrongHostWithSslParameters
redis.clients.jedis.tls.RedisClusterClientIT ‑ connectWrongHost
redis.clients.jedis.tls.RedisClusterClientIT ‑ connectWrongHostWithSslParameters
redis.clients.jedis.tls.RedisSentinelClientIT ‑ connectWithWrongHost
redis.clients.jedis.tls.RedisSentinelClientIT ‑ connectWrongHostWithSslParameters
This pull request skips 407 tests.
redis.clients.jedis.commands.commandobjects.CommandObjectsStringCommandsTest[1] ‑ testMsetexNx_parametrized(String, MSetExParams)[1]
redis.clients.jedis.commands.commandobjects.CommandObjectsStringCommandsTest[1] ‑ testMsetexNx_parametrized(String, MSetExParams)[2]
redis.clients.jedis.commands.commandobjects.CommandObjectsStringCommandsTest[1] ‑ testMsetexNx_parametrized(String, MSetExParams)[3]
redis.clients.jedis.commands.commandobjects.CommandObjectsStringCommandsTest[1] ‑ testMsetexNx_parametrized(String, MSetExParams)[4]
redis.clients.jedis.commands.commandobjects.CommandObjectsStringCommandsTest[1] ‑ testMsetexNx_parametrized(String, MSetExParams)[5]
redis.clients.jedis.commands.commandobjects.CommandObjectsStringCommandsTest[2] ‑ testMsetexNx_parametrized(String, MSetExParams)[1]
redis.clients.jedis.commands.commandobjects.CommandObjectsStringCommandsTest[2] ‑ testMsetexNx_parametrized(String, MSetExParams)[2]
redis.clients.jedis.commands.commandobjects.CommandObjectsStringCommandsTest[2] ‑ testMsetexNx_parametrized(String, MSetExParams)[3]
redis.clients.jedis.commands.commandobjects.CommandObjectsStringCommandsTest[2] ‑ testMsetexNx_parametrized(String, MSetExParams)[4]
redis.clients.jedis.commands.commandobjects.CommandObjectsStringCommandsTest[2] ‑ testMsetexNx_parametrized(String, MSetExParams)[5]
…

♻️ This comment has been updated with latest results.

@ggivo ggivo added the bug label Apr 23, 2026
@ggivo ggivo added this to the 8.0.0 milestone Apr 23, 2026
@ggivo ggivo marked this pull request as ready for review April 23, 2026 10:50
@ggivo ggivo requested review from atakavci, tishun and uglide April 23, 2026 11:59

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 36fed37. Configure here.

Comment thread src/main/java/redis/clients/jedis/DefaultJedisClientConfig.java
Comment thread src/main/java/redis/clients/jedis/JedisClientConfig.java
Comment thread src/main/java/redis/clients/jedis/JedisClientConfig.java
Comment thread src/test/resources/endpoints.json
…ters config

Mark legacy SSL configuration (ssl, sslSocketFactory, sslParameters getters and
builder setters) as @deprecated since 7.4.2 in favor of SslOptions, and update
JedisClientConfig / SslOptions Javadoc.
@ggivo ggivo merged commit dd8ea11 into master Apr 24, 2026
19 checks passed
ggivo added a commit that referenced this pull request Apr 24, 2026
…S connections (#4497)

* Enforce hostname verification by default for TLS connections

Enable HTTPS endpoint identification algorithm by default in DefaultJedisSocketFactory
when ssl(true) is used without custom SSLParameters.
Add tests (Jedis, RedisClient, RedisClusterClient, RedisSentinelClient) to
verify hostname verification failure when certificate CN/SAN doesn't match the
connection hostname.

Users can still override by providing custom SSLParameters.

Fixes: CAE-2794

* DefaultJedisClientConfig#builder(URI redisUri)  updated to SslOptions

* Revert "DefaultJedisClientConfig#builder(URI redisUri)  updated to SslOptions"

This reverts commit 36fed37.

* docs(ssl): recommend SslOptions; deprecate SSLSocketFactory/SSLParameters config

Mark legacy SSL configuration (ssl, sslSocketFactory, sslParameters getters and
builder setters) as @deprecated since 7.4.2 in favor of SslOptions, and update
JedisClientConfig / SslOptions Javadoc.
@ggivo ggivo deleted the topic/ggivo/tls-enforce-full-certificate-validation branch May 21, 2026 08:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants