今天从同事那里了解到一个接口 org.apache.struts2.interceptor.NoParameters,之前从来没用过,私下研究了一下觉得很有用,记下来留作以后参考:
NoParameters.java,源码附上:
注释的意思是说实现该接口的Action类,不会对任何参数自动赋值,却支持手动赋值,那么我们在什么情况下不需要struts替我们自动赋值请求参数呢?下面再看一个拦截器:
ParametersInterceptor.java,源码附上:
从ParameterInterceptor可以看到,如果Action类没有实现NoParameters接口,且此时的日志模式为debug,那么ParameterInterceptor拦截器会把所有的请求参数打印出来,打印请求参数这原本是件好事,可以有助于开发人员及时定位问题。但是如果请求参数中包含明文的密码时,那么用户的密码就会暴露在日志文件中,从而被有权限的查看日志的人窃取到密码。
项目中请求走的是https协议,项目的安全官认为https协议会对报文整体进行加密,所以对于 请求参数包含密码的这种情况,没有必要对密码再次加密,所以导致密码明文传到后台。
这个时候NoParameters就起作用了,只要将Action实现NoParameters接口,那么执行到 ParameterInterceptor时就会跳过打印请求参数的分支,此时Action中的参数不支持自动赋值,倒是可以通过request.getParameter的方式获取到请求参数。
附加内容:
源码中有一段很奇怪的代码:
如果日志级别高于debug,debug日志内容是不会打出来的,那么为什么还要在打印debug日志前要做是否为debug模式的判断呢?
原来是出于性能的考虑, 如果没有了debug级别的预判,无论此时日志级别是否为debug,getParameterLogMap方法都是被执行的。那么以后对于打印日志的内容比较耗性能,就有必要在打印前做日志级别的预判。
NoParameters.java,源码附上:
package org.apache.struts2.interceptor;
/**
* This marker interface should be implemented by actions that do not want any parameters set on
* them automatically. This may be useful if one is using the action tag and want to supply
* the parameters to the action manually using the param tag. It may also be useful if one for
* security reasons wants to make sure that parameters cannot be set by malicious users.
*
*/
public interface NoParameters extends com.opensymphony.xwork2.interceptor.NoParameters
{
}
注释的意思是说实现该接口的Action类,不会对任何参数自动赋值,却支持手动赋值,那么我们在什么情况下不需要struts替我们自动赋值请求参数呢?下面再看一个拦截器:
ParametersInterceptor.java,源码附上:
@Override
public String doIntercept(ActionInvocation invocation) throws Exception {
Object action = invocation.getAction();
if (!(action instanceof NoParameters)) {
ActionContext ac = invocation.getInvocationContext();
final Map<String, Object> parameters = retrieveParameters(ac);
if (LOG.isDebugEnabled()) {
LOG.debug("Setting params " + getParameterLogMap(parameters));
}
if (parameters != null) {
Map<String, Object> contextMap = ac.getContextMap();
try {
ReflectionContextState.setCreatingNullObjects(contextMap, true);
ReflectionContextState.setDenyMethodExecution(contextMap, true);
ReflectionContextState.setReportingConversionErrors(contextMap, true);
ValueStack stack = ac.getValueStack();
setParameters(action, stack, parameters);
} finally {
ReflectionContextState.setCreatingNullObjects(contextMap, false);
ReflectionContextState.setDenyMethodExecution(contextMap, false);
ReflectionContextState.setReportingConversionErrors(contextMap, false);
}
}
}
return invocation.invoke();
}
从ParameterInterceptor可以看到,如果Action类没有实现NoParameters接口,且此时的日志模式为debug,那么ParameterInterceptor拦截器会把所有的请求参数打印出来,打印请求参数这原本是件好事,可以有助于开发人员及时定位问题。但是如果请求参数中包含明文的密码时,那么用户的密码就会暴露在日志文件中,从而被有权限的查看日志的人窃取到密码。
项目中请求走的是https协议,项目的安全官认为https协议会对报文整体进行加密,所以对于 请求参数包含密码的这种情况,没有必要对密码再次加密,所以导致密码明文传到后台。
这个时候NoParameters就起作用了,只要将Action实现NoParameters接口,那么执行到 ParameterInterceptor时就会跳过打印请求参数的分支,此时Action中的参数不支持自动赋值,倒是可以通过request.getParameter的方式获取到请求参数。
附加内容:
源码中有一段很奇怪的代码:
if (LOG.isDebugEnabled()) {
LOG.debug("Setting params " + getParameterLogMap(parameters));
}
如果日志级别高于debug,debug日志内容是不会打出来的,那么为什么还要在打印debug日志前要做是否为debug模式的判断呢?
原来是出于性能的考虑, 如果没有了debug级别的预判,无论此时日志级别是否为debug,getParameterLogMap方法都是被执行的。那么以后对于打印日志的内容比较耗性能,就有必要在打印前做日志级别的预判。