简体   繁体   中英

CSRF token generation issue

To prevent CSRF below were the steps i have followed:

1 . First time when request comes(to loginfilter) session is null, create a session add token(randome number) to this new session by using setAttribute() and redirect to login.jsp screen using dispatcher.forward .

2 . in login.jsp screen use getAttribute() store the token in the hidden filed.

3 . on submit of login.jsp first request will come to loginfilter, here compare the token from the request with the token in the session, if matches then proceed with executing the action class. otherwise generate the new token for the same session and redirect to the login.jsp using sendRedirect()

when i ran the security tool on this application, i message saying "Missing one time token parameter".

Please help me.


1.filter.java

if (session == null) {
    chain.doFilter(request, response);
    return;
}
else {
    // validate the CSRF
    String sToken = httprequest.getSession().getAttribute("CSRF_TOKEN")
            .toString();
    String pToken = httprequest.getParameter("CSRF_TOKEN");
    System.out.println("Tokens - " + sToken + pToken);
    if (sToken.equals(pToken)) {
        chain.doFilter(request, response);
    }
    else {
        CommonUtils.updateSessionToken(session);
        /*
         * RequestDispatcher rd =
         * request.getRequestDispatcher("/login.jsp");
         * rd.forward(request, response);
         */
        httpresponse.sendRedirect("/login.jsp");
    }
}

2.login.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%
    Object token = request.getSession().getAttribute("CSRF_TOKEN");
    String tokenStr = "";
    if (token != null) {
        tokenStr = (String) token;
    }

    System.out.println("+tokenStr " + tokenStr);
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>CSRFGuard Test Application</title>
</head>
<body>
    Welcome to the OWASP CSRFGuard Test Application! Where would you like
    to go?
    <br />
    <form action="/CSRF/helloServlet" method="post">
        <input type="text" name="username" /> <br /> <input type="text"
            value="<%=tokenStr%>" name="CSRF_TOKEN" /> <input type="submit"
            value="login">
    </form>
</body>
</html>

3.web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>CSRF</display-name>
    <servlet>
        <description>
        </description>
        <display-name>Hell0oServelt</display-name>
        <servlet-name>HelloServelt</servlet-name>
        <servlet-class>com.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServelt</servlet-name>
        <url-pattern>/helloServlet</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>login.jsp</welcome-file>
    </welcome-file-list>

        <listener>
        <listener-class>com.CsrfGuardHttpSessionListener</listener-class>
    </listener>
  <filter>
    <filter-name>LoggedInFilter</filter-name>
    <filter-class>com.LoggedInFilter</filter-class>
  </filter>

  <filter-mapping>
    <filter-name>LoggedInFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

</web-app>

4.CsrfGuardHttpSessionListener


public class CsrfGuardHttpSessionListener implements HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent event) {
        HttpSession session = event.getSession();
        System.out.println("New session id - "+session.getId());
        String tokenId = generateRandomId();
    session.setAttribute("CSRF_TOKEN", tokenId);
    System.out.println("newtoken -"+tokenId);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
        /** nothing to do  **/
    }

}

5.HelloServlet


public class HelloServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public HelloServlet() {
        super();
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Welcome ...!");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        doPost(req, resp);
    }
}

On redirect the browser is simply instructed to make a new request to login.jsp. This login page would not have the token set in hidden field unless you are using some framework which can help you with that. So instead use request dispatcher forward. Also you mentioned that you ran a security tool. If it is a tool which mimics requests then make sure to include the token in the replay second request or it will not be recognized.

EDIT (After code was posted): I did not get the reasoning of using a listener. What you wanted to achieve is that whenever a session is created you automatically associate a token with it. This you can do in your filter class as well. Please note that the httpRequest.getSession checks for the session and if not present it creates as well. There are other variants of this method which take boolean parameter. Also you need to understand that when you do chain.doFilter(request, response) it means that the request processing to proceed further in the chain.

You can take help from other popular CSRF filter implementations like here , here . Also you can take a look at sample posted here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM