Aias00 opened a new pull request, #4260:
URL: https://github.com/apache/hertzbeat/pull/4260

   ## Summary
   Fixes a silent TLS-to-plaintext downgrade in the R2DBC MySQL collector route.
   
   ### Vulnerability
   `MysqlR2dbcQueryExecutor.execute` first tried `SslMode.PREFERRED`; if that 
errored with a handshake-style failure (`handshake_failure`, `ssl/tls 
handshake`, `ClosedChannelException`, `connection unexpectedly closed`), it 
retried with `SslMode.DISABLED`:
   
   ```java
   QueryResult firstAttempt = executeOnce(normalizedSql, options, 
SslMode.PREFERRED);
   if (!firstAttempt.hasError() || 
!shouldRetryWithoutSsl(firstAttempt.getError())) {
       return firstAttempt;
   }
   QueryResult fallbackAttempt = executeOnce(normalizedSql, options, 
SslMode.DISABLED);
   ```
   
   A TLS handshake failure is **ambiguous** — a MitM can deliberately disrupt 
the handshake to trigger this fallback. Retrying with SSL disabled then 
authenticates the monitoring user to the (possibly tampered) endpoint over 
plaintext, exposing the credentials. Classic SSL-strip/downgrade.
   
   ### Fix
   Drop the error-triggered `DISABLED` retry and surface the failure instead.
   
   `SslMode.PREFERRED` already handles the legitimate plaintext case safely: 
when the server advertises no SSL capability in the initial handshake, the 
driver falls back to plaintext via protocol negotiation **without error**. So 
the explicit `DISABLED` retry only ever fired on errors — exactly the unsafe 
path. The `caching_sha2_password` / `must require ssl` diagnostic is preserved 
(now checked against the single attempt's error).
   
   ### Behavior after the fix
   | Server | Before | After |
   |---|---|---|
   | Supports TLS | TLS ✅ | TLS ✅ |
   | No SSL capability (clean) | plaintext via PREFERRED ✅ | plaintext via 
PREFERRED ✅ (unchanged) |
   | TLS handshake *fails* | **downgrade to plaintext** ❌ | fail closed with 
the error ✅ |
   | `caching_sha2_password`, runtime can't TLS | tailored error message | 
tailored error message (unchanged) |
   
   The only behavior change is the third row — the dangerous one — which now 
fails closed.
   
   ### Verification
   - `mvn -pl hertzbeat-collector/hertzbeat-collector-mysql-r2dbc -am compile` 
✅ (JDK 25)
   - `mvn -pl hertzbeat-collector/hertzbeat-collector-mysql-r2dbc -am 
checkstyle:check` ✅
   - Unit tests pass: `SqlGuardTest`, `ResultSetMapperTest`, 
`MysqlSqlTemplateCompatibilityTest` (7 tests) ✅
   - The Docker-based `MysqlR2dbcQueryExecutorIntegrationTest` exercises the 
success paths (no-SSL and SSL-capable servers) via `PREFERRED` and is 
unaffected by this change; it requires Docker so was not run locally.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to