🎨 #4130 【小程序】【开放平台】优化代码,防止 code2Session 凭证通过异常和日志泄露
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
package me.chanjar.weixin.common.util.http;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import me.chanjar.weixin.common.error.WxError;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.error.WxRuntimeException;
|
||||
|
||||
/**
|
||||
* Safe parameter and exception handling for requests containing credentials.
|
||||
*/
|
||||
public final class SensitiveRequestUtils {
|
||||
private SensitiveRequestUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes one raw query parameter value, without interpreting existing percent escapes.
|
||||
*
|
||||
* @param value raw, non-null parameter value
|
||||
* @return UTF-8 form-encoded value
|
||||
* @throws NullPointerException if the value is null
|
||||
*/
|
||||
public static String encodeQueryValue(String value) {
|
||||
try {
|
||||
return URLEncoder.encode(value, StandardCharsets.UTF_8.name());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new IllegalStateException("UTF-8 is not available");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retains the WeChat error code and stack frames without exposing response data or causes.
|
||||
* This is intended for credential-bearing entry points, not general exception conversion.
|
||||
*
|
||||
* @param failure original failure
|
||||
* @return safe exception without the original message, JSON, cause or suppressed exceptions
|
||||
*/
|
||||
public static WxErrorException sanitize(WxErrorException failure) {
|
||||
WxErrorException safe = new WxErrorException(new WxError(failure.getError().getErrorCode(),
|
||||
"Sensitive request failed"));
|
||||
safe.setStackTrace(failure.getStackTrace());
|
||||
return safe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes request data from a runtime failure. Common argument, state and null failures
|
||||
* keep their categories; other runtime failures become {@link WxRuntimeException}.
|
||||
* Original exception class names and stack frames remain available for diagnosis.
|
||||
*
|
||||
* @param failure original failure
|
||||
* @return safe exception without the original message, cause or suppressed exceptions
|
||||
*/
|
||||
public static RuntimeException sanitize(RuntimeException failure) {
|
||||
String message = "Sensitive request failed (" + failure.getClass().getName() + ")";
|
||||
RuntimeException safe;
|
||||
if (failure instanceof IllegalArgumentException) {
|
||||
safe = new IllegalArgumentException(message);
|
||||
} else if (failure instanceof IllegalStateException) {
|
||||
safe = new IllegalStateException(message);
|
||||
} else if (failure instanceof NullPointerException) {
|
||||
safe = new NullPointerException(message);
|
||||
} else {
|
||||
safe = new WxRuntimeException(message);
|
||||
}
|
||||
safe.setStackTrace(failure.getStackTrace());
|
||||
return safe;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package me.chanjar.weixin.common.util.http;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.net.URLDecoder;
|
||||
import me.chanjar.weixin.common.error.WxError;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.error.WxRuntimeException;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class SensitiveRequestUtilsTest {
|
||||
@Test
|
||||
public void encodesRawValuesExactlyOnce() throws Exception {
|
||||
for (String value : new String[]{"NORMAL_CODE", "", "a b\n", "+&=#?%2F", "中文\uD83D\uDE00"}) {
|
||||
String encoded = SensitiveRequestUtils.encodeQueryValue(value);
|
||||
assertEquals(URLDecoder.decode(encoded, "UTF-8"), value);
|
||||
assertFalse(encoded.contains("&"));
|
||||
assertFalse(encoded.contains("#"));
|
||||
}
|
||||
assertEquals(SensitiveRequestUtils.encodeQueryValue("%2F"), "%252F");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void doesNotConvertNullToAValue() {
|
||||
SensitiveRequestUtils.encodeQueryValue(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removesAllOriginalErrorRepresentations() {
|
||||
WxError error = WxError.builder().errorCode(40029).errorMsg("FAKE_SECRET")
|
||||
.errorMsgEn("FAKE_SECRET").json("FAKE_SECRET").build();
|
||||
WxErrorException original = new WxErrorException(error, new IllegalArgumentException("FAKE_SECRET"));
|
||||
original.addSuppressed(new IllegalStateException("FAKE_SECRET"));
|
||||
WxErrorException safe = SensitiveRequestUtils.sanitize(original);
|
||||
assertEquals(safe.getError().getErrorCode(), 40029);
|
||||
assertNull(safe.getError().getJson());
|
||||
assertNull(safe.getError().getErrorMsgEn());
|
||||
assertSafe(safe, original);
|
||||
assertEquals(original.getError().getJson(), "FAKE_SECRET");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void retainsCommonRuntimeCategoriesWithoutCauses() {
|
||||
for (RuntimeException original : new RuntimeException[]{new IllegalArgumentException("FAKE_SECRET"),
|
||||
new IllegalStateException("FAKE_SECRET"), new NullPointerException("FAKE_SECRET"),
|
||||
new WxRuntimeException("FAKE_SECRET")}) {
|
||||
original.initCause(new RuntimeException("FAKE_SECRET"));
|
||||
original.addSuppressed(new RuntimeException("FAKE_SECRET"));
|
||||
RuntimeException safe = SensitiveRequestUtils.sanitize(original);
|
||||
assertEquals(safe.getClass(), original.getClass());
|
||||
assertSafe(safe, original);
|
||||
}
|
||||
assertTrue(SensitiveRequestUtils.sanitize(new UnsupportedOperationException("FAKE_SECRET"))
|
||||
instanceof WxRuntimeException);
|
||||
}
|
||||
|
||||
private void assertSafe(Throwable safe, Throwable original) {
|
||||
StringWriter trace = new StringWriter();
|
||||
safe.printStackTrace(new PrintWriter(trace));
|
||||
assertFalse(trace.toString().contains("FAKE_SECRET"));
|
||||
assertNull(safe.getCause());
|
||||
assertEquals(safe.getSuppressed().length, 0);
|
||||
assertEquals(safe.getStackTrace(), original.getStackTrace());
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
<suite name="Weixin-java-tool-suite" verbose="1">
|
||||
<test name="Bean_Test">
|
||||
<classes>
|
||||
<class name="me.chanjar.weixin.common.util.http.SensitiveRequestUtilsTest"/>
|
||||
<class name="me.chanjar.weixin.common.bean.WxAccessTokenTest"/>
|
||||
<class name="me.chanjar.weixin.common.error.WxErrorTest"/>
|
||||
<class name="me.chanjar.weixin.common.bean.WxMenuTest"/>
|
||||
|
||||
Reference in New Issue
Block a user