From 50605d6dadb8a366a172950adf4af1b5fd581931 Mon Sep 17 00:00:00 2001 From: Sreekanth Vadigi Date: Thu, 18 Jun 2026 10:14:42 +0000 Subject: [PATCH] Redact Azure and GCS presigned URL credentials in logs RequestSanitizer only redacted three AWS query params (case-sensitively), so Azure SAS (sig) and GCS (X-Goog-Signature/Credential) presigned URLs were logged with usable credentials. Extends the redaction set to cover all three clouds and matches case-insensitively. Co-authored-by: Isaac Signed-off-by: Sreekanth Vadigi --- NEXT_CHANGELOG.md | 1 + .../dbclient/impl/http/RequestSanitizer.java | 18 ++++++++-- .../impl/http/RequestSanitizerTest.java | 35 +++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index a972de65e2..f516b04505 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -7,6 +7,7 @@ ### Updated ### Fixed +- Fixed presigned URL credentials not being fully redacted in logs. - Fixed `setCatalog()` and `setSchema()` producing invalid SQL (e.g. `SET CATALOG ``name``) when the catalog or schema name was passed already wrapped in backticks. Backticks are now stripped before wrapping, and `getCatalog()`/`getSchema()` return the bare identifier name. - Fixed metadata SQL generation for catalog, schema, and table identifiers containing backticks. - Fixed SEA result truncation when direct results are disabled. Large, highly-compressible results that span multiple chunks were delivered inline via the old hybrid path and truncated to the first chunk. The SQL Execution path now uses an async (`0s`) wait timeout when direct results are disabled, so results are returned via external links and fetched in full. diff --git a/src/main/java/com/databricks/jdbc/dbclient/impl/http/RequestSanitizer.java b/src/main/java/com/databricks/jdbc/dbclient/impl/http/RequestSanitizer.java index e31e14ddba..d20d455de9 100644 --- a/src/main/java/com/databricks/jdbc/dbclient/impl/http/RequestSanitizer.java +++ b/src/main/java/com/databricks/jdbc/dbclient/impl/http/RequestSanitizer.java @@ -3,11 +3,25 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.List; +import java.util.Set; +import java.util.TreeSet; import org.apache.http.client.methods.HttpUriRequest; public class RequestSanitizer { - private static final List SENSITIVE_QUERY_PARAMS = - List.of("X-Amz-Security-Token", "X-Amz-Signature", "X-Amz-Credential"); + // Signature/credential params in AWS, Azure (sig) and GCS presigned URLs. + private static final Set SENSITIVE_QUERY_PARAMS = + new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + + static { + SENSITIVE_QUERY_PARAMS.addAll( + List.of( + "X-Amz-Security-Token", + "X-Amz-Signature", + "X-Amz-Credential", + "sig", + "X-Goog-Signature", + "X-Goog-Credential")); + } public static String sanitizeRequest(HttpUriRequest request) { try { diff --git a/src/test/java/com/databricks/jdbc/dbclient/impl/http/RequestSanitizerTest.java b/src/test/java/com/databricks/jdbc/dbclient/impl/http/RequestSanitizerTest.java index 075f5b8719..fa6f4d87a1 100644 --- a/src/test/java/com/databricks/jdbc/dbclient/impl/http/RequestSanitizerTest.java +++ b/src/test/java/com/databricks/jdbc/dbclient/impl/http/RequestSanitizerTest.java @@ -25,6 +25,41 @@ public void testSanitizeRequest_withSensitiveParams() { assertEquals(expectedUri, sanitizedUri); } + @Test + public void testSanitizeRequest_withAzureSasSignature() { + String originalUri = + "https://acct.blob.core.windows.net/c/chunk.arrow?sv=2021-08-06&se=2026-06-18T00:00Z&sr=b&sp=r&sig=secretSasSignature"; + String sanitizedUri = RequestSanitizer.sanitizeRequest(new HttpGet(originalUri)); + + // sig (the SAS credential) is redacted; non-secret metadata is preserved. + String expectedUri = + "https://acct.blob.core.windows.net/c/chunk.arrow?sv=2021-08-06&se=2026-06-18T00:00Z&sr=b&sp=r&sig=REDACTED"; + assertEquals(expectedUri, sanitizedUri); + } + + @Test + public void testSanitizeRequest_withGcsV4Signature() { + String originalUri = + "https://storage.googleapis.com/bucket/chunk.arrow?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=svc&X-Goog-Signature=secretSig"; + String sanitizedUri = RequestSanitizer.sanitizeRequest(new HttpGet(originalUri)); + + String expectedUri = + "https://storage.googleapis.com/bucket/chunk.arrow?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=REDACTED&X-Goog-Signature=REDACTED"; + assertEquals(expectedUri, sanitizedUri); + } + + @Test + public void testSanitizeRequest_withLowercaseGcsSignature() { + // GCS tooling may emit lowercase param names; matching must be case-insensitive. + String originalUri = + "https://storage.googleapis.com/bucket/chunk.arrow?x-goog-credential=svc&x-goog-signature=secretSig"; + String sanitizedUri = RequestSanitizer.sanitizeRequest(new HttpGet(originalUri)); + + String expectedUri = + "https://storage.googleapis.com/bucket/chunk.arrow?x-goog-credential=REDACTED&x-goog-signature=REDACTED"; + assertEquals(expectedUri, sanitizedUri); + } + @Test public void testSanitizeRequest_withNoSensitiveParams() { String originalUri = "https://example.com/api?param1=value1¶m2=value2";