在Struts中拦截XSS攻击可以通过配置拦截器来实现。以下是一个示例代码来演示如何在Struts中拦截XSS攻击:
创建XSS拦截器类
- 创建一个XSS拦截器类,实现
com.opensymphony.xwork2.interceptor.Interceptor
接口。import com.hoau.hbdp.framework.define.Protocol; import com.hoau.hbdp.framework.server.context.AppContext; import com.hoau.hbdp.framework.server.web.interceptor.AbstractInterceptor; import com.hoau.hbdp.framework.server.web.result.json.JSONPopulator; import com.hoau.hbdp.framework.server.web.result.json.annotation.JSON; import com.hoau.hbdp.framework.server.web.xss.ParametersValidatorException; import com.opensymphony.xwork2.ActionInvocation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts2.ServletActionContext; import org.codehaus.jackson.map.ObjectMapper; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.ReflectionUtils; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.lang.reflect.Method; import java.util.Map; import java.util.regex.Pattern; /** * @author * @desc 防存储箱Xss攻击 * @date 2023/11/06 10:43 **/ public class XssInterceptor extends AbstractInterceptor { private static final long serialVersionUID = -3423290391156261612L; private final Log log = LogFactory.getLog(getClass()); /** * 序列化及缓存类 */ private static final ObjectMapper MAPPER = new ObjectMapper(); /** * JSON格式反序列化并绑定到Action中的属性上 * * @param invocation * @return * @throws Exception * @since: * @see com.opensymphony.xwork2.interceptor.AbstractInterceptor#intercept(ActionInvocation) * intercept */ @Override public String intercept(ActionInvocation invocation) throws Exception { HttpServletRequest request = ServletActionContext.getRequest(); HttpServletResponse response = ServletActionContext.getResponse(); String contentType = request.getHeader("content-type"); if (contentType != null) { int iSemicolonIdx = contentType.indexOf(';'); if (iSemicolonIdx != -1) { contentType = contentType.substring(0, iSemicolonIdx); } } Object rootObject = invocation.getAction(); Class<?> clazz = invocation.getAction().getClass(); String methodName = invocation.getProxy().getMethod(); Method method = ReflectionUtils.findMethod(clazz, methodName); //如果在Action方法上加入JSON的注解,那么就可以在应用这个方法的时候,把错误的结果信息转换为json if (Protocol.JSON_CONTENT_TYPE.equalsIgnoreCase(contentType) || AnnotationUtils.isAnnotationDeclaredLocally(JSON.class, clazz) || (method != null && method.isAnnotationPresent(JSON.class))) { BufferedReader reader = request.getReader(); int bytesRead; StringBuilder stringBuilder = new StringBuilder(); char[] charBuffer = new char[2048]; while ((bytesRead = reader.read(charBuffer)) > 0) { stringBuilder.append(charBuffer, 0, bytesRead); } if (stringBuilder.toString().length() > 0) { //过滤参数 try { String valuestr = AppContext.getParametersValidator().doValidator(stringBuilder.toString(), response); valuestr = stripXSS(valuestr); @SuppressWarnings("rawtypes") Map json = MAPPER.readValue(valuestr, Map.class); JSONPopulator.populateObject(rootObject, json); } catch (ParametersValidatorException e) { return "success"; } } } else { if (log.isDebugEnabled()) { log.debug("Content type must be 'application/json' or 'application/json-rpc'. Ignoring request with content type " + contentType); } } return invocation.invoke(); } private String stripXSS(String value) { if (value != null) { value = value.replaceAll("", ""); Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(""); // Avoid anything in a src='...' type of expression scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); // Remove any lonesome </script> tag scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(""); // Remove any lonesome <script ...> tag scriptPattern = Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); // Avoid eval(...) expressions scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); // Avoid expression(...) expressions scriptPattern = Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); // Avoid javascript:... expressions scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(""); // Avoid vbscript:... expressions scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(""); // Avoid onload= expressions scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); scriptPattern = Pattern.compile("onerror(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); value = value.replaceAll(">", "〉").replaceAll("<", "〈"); } return value; } @Override public void init() { super.init(); } }
在上述代码中,我们使用
AbstractInterceptor
作为基类,实现了intercept
方法,该方法会在请求被处理之前拦截并进行XSS过滤。我们获取请求的参数,并对每个参数的值进行sanitize
方法的调用,该方法用于执行XSS过滤逻辑。
配置文件
在Struts的配置文件(如struts.xml)中配置拦截器。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="struts-default" extends="framework-default">
<interceptors>
<interceptor name="json" class="com.example.framework.server.web.interceptor.JSONInterceptor"/>
<interceptor name="xssInterceptor" class="com.example.XSSInterceptor" />
<interceptor-stack name="xssInterceptorStack">
<interceptor-ref name="xssInterceptor" />
<interceptor-ref name="json" />
</interceptor-stack>
</interceptors>
</package>
</struts>
注意点
在 struts.xml中 <interceptor-ref name="xssInterceptor" /> 前面不能配置拦截参数,不然就会一直获取不到参数,如我之前 <interceptor-ref name="json" /> 在前面导致一直XSSInterceptor拦截器中一直获取不到参数