diff --git a/src/main/java/net/snowflake/client/jdbc/SnowflakeFileTransferAgent.java b/src/main/java/net/snowflake/client/jdbc/SnowflakeFileTransferAgent.java index ba4e4f1a6..046132188 100644 --- a/src/main/java/net/snowflake/client/jdbc/SnowflakeFileTransferAgent.java +++ b/src/main/java/net/snowflake/client/jdbc/SnowflakeFileTransferAgent.java @@ -70,6 +70,7 @@ import net.snowflake.client.log.ArgSupplier; import net.snowflake.client.log.SFLogger; import net.snowflake.client.log.SFLoggerFactory; +import net.snowflake.client.util.SecretDetector; import net.snowflake.common.core.FileCompressionType; import net.snowflake.common.core.RemoteStoreFileEncryptionMaterial; import net.snowflake.common.core.SqlState; @@ -1337,7 +1338,8 @@ private static JsonNode parseCommandInGS(SFStatement statement, String command) } JsonNode jsonNode = (JsonNode) result; - logger.debug("Response: {}", jsonNode.toString()); + + logger.debug("Response: {}", SecretDetector.maskSecrets(jsonNode.toString())); SnowflakeUtil.checkErrorAndThrowException(jsonNode); return jsonNode; diff --git a/src/main/java/net/snowflake/client/util/SecretDetector.java b/src/main/java/net/snowflake/client/util/SecretDetector.java index 61fddc010..e2ea5e8dc 100644 --- a/src/main/java/net/snowflake/client/util/SecretDetector.java +++ b/src/main/java/net/snowflake/client/util/SecretDetector.java @@ -79,6 +79,9 @@ public class SecretDetector { "(token|assertion content)" + "(['\"\\s:=]+)" + "([a-z0-9=/_\\-+]{8,})", Pattern.CASE_INSENSITIVE); + private static final Pattern ENCRYPTION_MATERIAL_PATTERN = + Pattern.compile("\"encryptionMaterial\"\\s*:\\s*\\{.*?\\}", Pattern.CASE_INSENSITIVE); + // only attempt to find secrets in its leading 100Kb SNOW-30961 private static final int MAX_LENGTH = 100 * 1000; @@ -222,7 +225,9 @@ public static String maskSASToken(String text) { public static String maskSecrets(String text) { return filterAccessTokens( filterConnectionTokens( - filterPassword(filterSASTokens(filterAWSKeys(filterOAuthTokens(text)))))); + filterPassword( + filterSASTokens( + filterAWSKeys(filterOAuthTokens(filterEncryptionMaterial(text))))))); } /** @@ -283,6 +288,23 @@ public static String filterAccessTokens(String message) { return message; } + /** + * Filter encryption material that may be buried inside a JSON string. + * + * @param message the message text which may contain encryption material + * @return Return filtered message + */ + public static String filterEncryptionMaterial(String message) { + Matcher matcher = + ENCRYPTION_MATERIAL_PATTERN.matcher( + message.length() <= MAX_LENGTH ? message : message.substring(0, MAX_LENGTH)); + + if (matcher.find()) { + return matcher.replaceAll("\"encryptionMaterial\" : ****"); + } + return message; + } + public static JSONObject maskJsonObject(JSONObject json) { for (Map.Entry entry : json.entrySet()) { if (entry.getValue() instanceof String) { diff --git a/src/test/java/net/snowflake/client/util/SecretDetectorTest.java b/src/test/java/net/snowflake/client/util/SecretDetectorTest.java index 889192f83..f1e0594fd 100644 --- a/src/test/java/net/snowflake/client/util/SecretDetectorTest.java +++ b/src/test/java/net/snowflake/client/util/SecretDetectorTest.java @@ -421,4 +421,27 @@ public void testMaskJacksonObject() { "Nested Jackson array node is not masked successfully", maskedNestedArrayStr.equals(SecretDetector.maskJacksonNode(objNode4).toString())); } + + @Test + public void testEncryptionMaterialFilter() throws Exception { + String messageText = + "{\"data\":" + + "{\"autoCompress\":true," + + "\"overwrite\":false," + + "\"clientShowEncryptionParameter\":true," + + "\"encryptionMaterial\":{\"queryStageMasterKey\":\"asdfasdfasdfasdf==\",\"queryId\":\"01b6f5ba-0002-0181-0000-11111111da\",\"smkId\":1111}," + + "\"stageInfo\":{\"locationType\":\"AZURE\", \"region\":\"eastus2\"}"; + + String filteredMessageText = + "{\"data\":" + + "{\"autoCompress\":true," + + "\"overwrite\":false," + + "\"clientShowEncryptionParameter\":true," + + "\"encryptionMaterial\" : ****," + + "\"stageInfo\":{\"locationType\":\"AZURE\", \"region\":\"eastus2\"}"; + + String result = SecretDetector.filterEncryptionMaterial(messageText); + + assertEquals(filteredMessageText, result); + } }