1. 程式人生 > >Struts2 過濾CSRF攻擊的一種解決方案

Struts2 過濾CSRF攻擊的一種解決方案

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值驗證失敗後的處理情況,具體實現看實際專案的需要