临时抽调过来帮另一个项目组做特殊字符的过滤,首先想到的方案是Filter+HttpServletRequestWrapper,现成的代码都有直接迁移过来就可以。结果却是只有部分参数获取时进行了转换,而大多数并没有经过转换。
项目是Struts2 的项目,字符过滤的核心逻辑如下:
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values == null) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = charFilter(parameter,values[i]);
}
return encodedValues;
}
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
if (value == null) {
return null;
}
return charFilter(parameter,value);
}
charFilter
方法中对参数中指定的特殊字符进行替换,在调试效果时发现通过struts
值栈获取到的值并没有将参数中的特殊字符进行替换,只有显示通过request.getParameter(parameterName)
语句获取的参数才会进行特殊字符的处理。
走到这一步时我认为Filter+HttpServletRequestWrapper
对struts
的值栈并不会起作用,于是转而寻求利用struts
自身的机制~拦截器(Interceptor)来对请求参数进行过滤。
一切似乎很顺利,提交表单,预期的特殊字符均被替换掉了。提交代码,灾难来临,测试环境更新代码后所有的放大镜都不能正常工作了。debug代码,放大镜后台取参数时值为null,参数是JSON
格式的,
自定义拦截器的逻辑是从ActionContext中获取全部的参数,替换后再塞回去。
以为是替换特殊字符后导致JSON
格式错乱,故将取出的值直接塞回去,但Action
中取出的值仍是null
public String intercept(ActionInvocation invocation) throws Exception {
ActionContext actionContext = invocation.getInvocationContext();
ValueStack stack = actionContext.getValueStack();
Map valueTreeMap = actionContext.getParameters();
Iterator iterator = valueTreeMap.entrySet().iterator();
while (iterator.hasNext()) {
Entry entry = (Entry) iterator.next();
String key = (String) entry.getKey();
String[] oldValues = null;
if (entry.getValue() instanceof String) {
oldValues = new String[] { entry.getValue().toString() };
} else {
oldValues = (String[]) entry.getValue();
}
// 处理后的请求参数
String[] newValueStr = new String[oldValues.length];
// 对请求参数过滤处理
if (oldValues.length >= 1) {
for (int i = 0; i < oldValues.length; i++) {
newValueStr[i] = cleanXSS(oldValues[i].toString());
}
stack.set(key, entry.getValue());
valueTreeMap.put(key, entry.getValue());
}
}
String result = null;
try {
result = invocation.invoke();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
经过百度及多次尝试,发现重写HttpServletRequestWrapper
的getParameterMap()
可以解决过滤特殊字符无效的问题
public Map getParameterMap() {
Map paramMap = super.getParameterMap();
if (CollectionUtils.isEmpty(paramMap)) {
return paramMap;
}
for (Object value : paramMap.values()) {
String[] str = (String[])value;
if (str != null) {
for (int i = 0; i < str.length; i++) {
str[i] = cleanXSS(str[i]);
}
}
}
return paramMap;
}