fix(order): validate V5Pay prefix before case folding

This commit is contained in:
zhx 2026-07-10 20:43:51 +08:00
parent 534574eb71
commit 58dd20c70a
2 changed files with 13 additions and 4 deletions

View File

@ -41,12 +41,12 @@ public final class V5PayOrderNoUtils {
private static String normalizedPrefix(String prefix) { private static String normalizedPrefix(String prefix) {
String value = Objects.toString(prefix, DEFAULT_PREFIX).trim(); String value = Objects.toString(prefix, DEFAULT_PREFIX).trim();
String normalized = (value.isBlank() ? DEFAULT_PREFIX : value).toUpperCase(Locale.ROOT); String rawPrefix = value.isBlank() ? DEFAULT_PREFIX : value;
if (!PREFIX_PATTERN.matcher(normalized).matches()) { if (!PREFIX_PATTERN.matcher(rawPrefix).matches()) {
// 无分隔订单号若允许数字前缀会产生命名空间碰撞符号和 Unicode 同样不符合支付方格式 // 必须在大小写转换前校验原文否则 ı/ß Unicode 可能折叠成 ASCII 并与合法命名空间碰撞
throw new IllegalArgumentException("V5Pay order prefix must contain only ASCII letters"); throw new IllegalArgumentException("V5Pay order prefix must contain only ASCII letters");
} }
return normalized; return rawPrefix.toUpperCase(Locale.ROOT);
} }
private static boolean isValidLocalOrderNo(String localOrderNo) { private static boolean isValidLocalOrderNo(String localOrderNo) {

View File

@ -48,6 +48,15 @@ public class V5PaySignUtilsTest {
assertInvalidOrderNo("1ASLAN", "23"); assertInvalidOrderNo("1ASLAN", "23");
} }
@Test
public void unicodeCaseFoldingCannotAliasAsciiNamespace() {
Assert.assertEquals("ASLANI23", V5PayOrderNoUtils.providerOrderNo("aslani", "23"));
Assert.assertEquals("ASSLAN23", V5PayOrderNoUtils.providerOrderNo("asslan", "23"));
// Java 大写会将 dotless-i sharp-s 折叠成 ASCII原文校验必须在转换之前完成
assertInvalidOrderNo("aslanı", "23");
assertInvalidOrderNo("aßlan", "23");
}
@Test @Test
public void orderParserRejectsOtherNamespaceEmptyAndIllegalCharacters() { public void orderParserRejectsOtherNamespaceEmptyAndIllegalCharacters() {
Assert.assertEquals("", V5PayOrderNoUtils.localOrderNo("ASLAN", "LALU123")); Assert.assertEquals("", V5PayOrderNoUtils.localOrderNo("ASLAN", "LALU123"));