Struts2 过滤CSRF攻击的一种解决方案

版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处! https://blog.csdn.net/huplion/article/details/49641409

CSRF(Cross-site request forgery跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站?的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,并且攻击方式几乎相左。XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。

它的防御方案包括如下四种:

1.检查http referer是否来自同一个域
2.限制session cookie的生命周期
3.验证码
4.使用token

在struts下自带了许多标签库
其中就有 s:token ,这个可以生成一次性token,把这个标签放在 s:form 里面可以在提交的时候自动带上token值;

<s:form action="login.action">
        <s:token name="token"></s:token>
        <s:fielderror name="errorInfo"></s:fielderror>
        <s:textfield name="username" key="user"></s:textfield>
        <s:textfield name="password" key="pass"></s:textfield>
        <s:submit key="login"></s:submit>
    </s:form>

然后在struts.xml的对应的action中引用就好了

          <param name="excludeMethods">....</param> //这里可以配置token拦截器的排队方法
<interceptor-ref name="token">
param name="excludeMethods">....</param> //这里可以配置token拦截器的排队方法
</interceptor-ref>
<result name=“invaild.token">/***.jsp</result>

一般情况下这个拦截器就配置完了
但是这个拦截器会把这个action的post 方法和get方法同时拦截掉。
如果我们只需要拦截post方法的请求应该怎么处理呢?
在这里我们自己实现一个拦截器只拦截post方法
实现如下

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.interceptor.TokenInterceptor;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class CsrfInterceptor extends AbstractInterceptor{

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        // TODO Auto-generated method stub
        ActionContext actionContext = invocation.getInvocationContext();
        HttpServletRequest request = (HttpServletRequest)actionContext.get(ServletActionContext.HTTP_REQUEST);  
        if (request.getMethod().equals("GET")) {
            return invocation.invoke();
        }
        String tokenName = request.getParameter("struts.token.name");
        if (tokenName == null) {
            return "invalid.token";
        }
        String token = request.getParameter(tokenName);
        if (token == null) {
            return "invalid.token";
        }
        String correctToken = (String) request.getSession().getAttribute("struts.tokens." + tokenName);
        if (token.equals(correctToken)) {
            actionContext.getSession().put("struts.tokens" + tokenName , null);
            return invocation.invoke();
        }else {
            return "invalid.token";
        }
    }
}

我们可以用配置一般拦截器的方法配置此拦截器,在此不再叙述。
需要注意的一点是,须在struts.xml下 action标签下配置此项

<result name="invalid.token">jsp/tokenError.jsp</result>

表示token值验证失败后的处理情况,具体实现看实际项目的需要

展开阅读全文

没有更多推荐了,返回首页