如何防止我的网络应用程序在java中遭受CSRF(跨站请求伪造)

Var*_*run 5 java csrf-protection

我试图阻止我的 Web 应用程序遭受 CSRF(跨站点请求伪造)我点击了此链接Link for CSRF

这是我尝试过的。为了在 Java 中实现这一机制,我选择使用两个过滤器,一个为每个请求创建盐,另一个用于验证它。由于用户请求和后续应验证的 POST 或 GET 不一定按顺序执行,因此我决定使用基于时间的缓存来存储有效盐字符串的列表。

第一个过滤器用于为请求生成新的盐并将其存储在缓存中,代码如下:

public class LoadSalt implements Filter{


    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        // Assume its HTTP  
        HttpServletRequest httpReq = (HttpServletRequest)request;
        // Check the user session for the salt cache, if none is present we create one
        @SuppressWarnings("unchecked")
        Cache<String, Boolean> csrfPreventionSaltCache = (Cache<String, Boolean>)
                httpReq.getSession().getAttribute("csrfPreventionSaltCache");

        System.out.println("Checking cahce befor creating it from Request :csrfPreventionSaltCache: "+csrfPreventionSaltCache);

        if(csrfPreventionSaltCache == null)
        {
            System.out.println("csrfPreventionSaltCache is null have to create new one");
            String csrfPreventionfromrequest = (String) httpReq.getSession().getAttribute("csrfPreventionSaltCache");
            System.out.println("csrfPreventionfromrequest :"+csrfPreventionfromrequest);

            // creating a new cache 
            csrfPreventionSaltCache = CacheBuilder.newBuilder().maximumSize(5000)
                    .expireAfterAccess(20, TimeUnit.MINUTES).build();

            // Setting to gttpReq
            httpReq.getSession().setAttribute("csrfPreventionSaltCache", csrfPreventionSaltCache);

            System.out.println("After setting the csrfPreventionSaltCache to HttpReq");
            System.out.println("--------csrfPreventionSaltCache------ :"+httpReq.getSession().getAttribute("csrfPreventionSaltCache"));
        }



        // Generate the salt and store it in the users cache
        String salt = RandomStringUtils.random(20, 0, 0, true, true, null, new SecureRandom());
        System.out.println("Salt: "+salt);
        csrfPreventionSaltCache.put(salt, Boolean.TRUE);
        // Add the salt to the current request so it can be used
        // by the page rendered in this request
        httpReq.setAttribute("csrfPreventionSalt", salt);

        System.out.println("Before going to validate salt checking for salt in request");
        System.out.println(" httpReq.getAttribute(csrfPreventionSalt) ----:"+httpReq.getAttribute("csrfPreventionSalt"));
       // System.out.println(" httpReq.getSession().getAttribute(csrfPreventionSalt) :----"+httpReq.getSession().getAttribute("csrfPreventionSalt"));


        chain.doFilter(request, response);
    }
    public void init(FilterConfig arg0) throws ServletException {

    }

    public void destroy() {

    }
}
Run Code Online (Sandbox Code Playgroud)

web.xml 中的映射

        <filter>
            <filter-name>loadSalt</filter-name>
            <filter-class>com.globalss.dnb.monitor.security.LoadSalt</filter-class>
        </filter>

        <filter-mapping>
             <filter-name>loadSalt</filter-name>
             <url-pattern>/*</url-pattern>
        </filter-mapping>
Run Code Online (Sandbox Code Playgroud)

为了在执行安全事务之前验证盐,我编写了另一个过滤器:

public class ValidateSalt implements Filter {

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        // Assume its HTTP
        HttpServletRequest httpReq = (HttpServletRequest) request;

        //String salt = (String) httpReq.getSession().getAttribute("csrfPreventionSalt");
        String salt =(String) httpReq.getAttribute("csrfPreventionSalt");
        System.out.println("I am in ValidateSalt : salt: "+salt);

     // Validate that the salt is in the cache
        @SuppressWarnings("unchecked")
        Cache<String, Boolean> csrfPreventionSaltCache = (Cache<String, Boolean>)
            httpReq.getSession().getAttribute("csrfPreventionSaltCache");


        if(csrfPreventionSaltCache !=null && salt !=null && csrfPreventionSaltCache.getIfPresent(salt)!=null)
        {
            // If the salt is in the cache, we move on
            chain.doFilter(request, response);
        }
        else
        {
            // Otherwise we throw an exception aborting the request flow
            throw new ServletException("Potential CSRF detected!! Inform a scary sysadmin ASAP.");
        }

    }

    public void init(FilterConfig arg0) throws ServletException {

    }
    public void destroy() {

    }

}
Run Code Online (Sandbox Code Playgroud)

web.xml 中第二个 Filetr 的映射

<filter>
            <filter-name>validateSalt</filter-name>
             <filter-class>com.globalss.dnb.monitor.security.ValidateSalt</filter-class>
        </filter>

        <filter-mapping>
            <filter-name>validateSalt</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
Run Code Online (Sandbox Code Playgroud)

配置完两个 servlet 后,所有安全请求都失败了:)。为了解决这个问题,我必须向以安全 URL 结尾的每个链接和表单帖子添加 csrfPreventionSalt 参数,其中包含具有相同名称的请求参数的值。例如,在 JSP 页面内的 HTML 表单中:

<form action="/transferMoneyServlet" method="get">
    <input type="hidden" name="csrfPreventionSalt" value="<c:out value='${csrfPreventionSalt}'/>"/>
    ...
</form>
Run Code Online (Sandbox Code Playgroud)

完成所有这些之后,我尝试尝试 CSRF,这就是我所做的

public class LoadSalt implements Filter{


    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        // Assume its HTTP  
        HttpServletRequest httpReq = (HttpServletRequest)request;
        // Check the user session for the salt cache, if none is present we create one
        @SuppressWarnings("unchecked")
        Cache<String, Boolean> csrfPreventionSaltCache = (Cache<String, Boolean>)
                httpReq.getSession().getAttribute("csrfPreventionSaltCache");

        System.out.println("Checking cahce befor creating it from Request :csrfPreventionSaltCache: "+csrfPreventionSaltCache);

        if(csrfPreventionSaltCache == null)
        {
            System.out.println("csrfPreventionSaltCache is null have to create new one");
            String csrfPreventionfromrequest = (String) httpReq.getSession().getAttribute("csrfPreventionSaltCache");
            System.out.println("csrfPreventionfromrequest :"+csrfPreventionfromrequest);

            // creating a new cache 
            csrfPreventionSaltCache = CacheBuilder.newBuilder().maximumSize(5000)
                    .expireAfterAccess(20, TimeUnit.MINUTES).build();

            // Setting to gttpReq
            httpReq.getSession().setAttribute("csrfPreventionSaltCache", csrfPreventionSaltCache);

            System.out.println("After setting the csrfPreventionSaltCache to HttpReq");
            System.out.println("--------csrfPreventionSaltCache------ :"+httpReq.getSession().getAttribute("csrfPreventionSaltCache"));
        }



        // Generate the salt and store it in the users cache
        String salt = RandomStringUtils.random(20, 0, 0, true, true, null, new SecureRandom());
        System.out.println("Salt: "+salt);
        csrfPreventionSaltCache.put(salt, Boolean.TRUE);
        // Add the salt to the current request so it can be used
        // by the page rendered in this request
        httpReq.setAttribute("csrfPreventionSalt", salt);

        System.out.println("Before going to validate salt checking for salt in request");
        System.out.println(" httpReq.getAttribute(csrfPreventionSalt) ----:"+httpReq.getAttribute("csrfPreventionSalt"));
       // System.out.println(" httpReq.getSession().getAttribute(csrfPreventionSalt) :----"+httpReq.getSession().getAttribute("csrfPreventionSalt"));


        chain.doFilter(request, response);
    }
    public void init(FilterConfig arg0) throws ServletException {

    }

    public void destroy() {

    }
}
Run Code Online (Sandbox Code Playgroud)

当我点击提交请求按钮时,我收到了成功响应,并且 CSRUser 已添加到我的数据库中。

我错过了什么吗?如何防止 CSRF 攻击?

Seo*_*Bro 1

您可以使用Spring Security进行用户身份验证和授权。从 Spring 3.2.0 版本开始,默认支持跨站请求伪造(CSRF) 。

您还可以使用 RequestMatcher 轻松排除不想保护的 URL:

public class CsrfSecurityRequestMatcher implements RequestMatcher {
private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
private RegexRequestMatcher unprotectedMatcher = new RegexRequestMatcher("/unprotected", null);

@Override
public boolean matches(HttpServletRequest request) {
    if(allowedMethods.matcher(request.getMethod()).matches()){
        return false;
    }

    return !unprotectedMatcher.matches(request);
}
}
Run Code Online (Sandbox Code Playgroud)

来源