【bugfix】密文传输+UrlEncode的坑

背景现象

服务之间的报文传输需要进行加密改造,发现上游发送过来表单请求(application/x-www-form-urlencoded)中的SM4密文解密不了

原因

客户端和服务端打印密文如下:

客户端打印密文:
U000AAEAAAAyAAAAAgAAAEAAAADYnadFTDMUfEBTv/STdyFPyUwhDRbdI+syV3Z9yvFh/hCNCugs5FUoCs4++I2dUQY4T5wIehN86Jc9KjSvWXmF
U000AAEAAAAyAAAAAgAAAEAAAADYnadFTDMUfEBTv/STdyFPyUwhDRbdI syV3Z9yvFh/hCNCugs5FUoCs4  I2dUQY4T5wIehN86Jc9KjSvWXmF
服务端打印密文

加密串中的加号+,到达服务端之后消失了,变成了一个空格

是因为表单请求到tomcat中处理的时候,会对表单的字段名称和字段值进行一次UrlDecode

String name;
String value;

if (decodeName) {
    urlDecode(tmpName);
}
tmpName.setCharset(charset);
name = tmpName.toString();

if (valueStart >= 0) {
    if (decodeValue) {
        urlDecode(tmpValue);
    }
    tmpValue.setCharset(charset);
    value = tmpValue.toString();
} else {
    value = "";
}

addParameter(name, value);

有69个字符:*+-./@_0-9a-zA-Z 不需要转码 ,算术加减乘除 4个,.小数点、@、 _下划线、数字10个、大小写26个字母 26*2 

其余所有字符都将被替换成百分号后跟两位十六进制数,解码也按照相反的规则,有的不在码表中的会保持原样但是+会被解成空格!!

解决方法

在客户端发送表单请求时,对表单字段的值进行UrlEncode

看一下业内最佳实践

如下是Spring-web中RestTemplate的实现,其中在写表单的时候进行了转码

URLEncoder.encode(name, charset.name()

restTemplate调用栈
protected String serializeForm(MultiValueMap<String, String> formData, Charset charset) {
	StringBuilder builder = new StringBuilder();
	formData.forEach((name, values) ->
		values.forEach(value -> {
			try {
				if (builder.length() != 0) {
					builder.append('&');
				}
				builder.append(URLEncoder.encode(name, charset.name()));
				if (value != null) {
					builder.append('=');
					builder.append(URLEncoder.encode(value, charset.name()));
				}
			}
			catch (UnsupportedEncodingException ex) {
				throw new IllegalStateException(ex);
			}
		}));
	return builder.toString();
}
发布了111 篇原创文章 · 获赞 98 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/sarafina527/article/details/104678156