如何防止我的Web应用程序在Java中出现CSRF(跨站点请求伪造) [英] How to prevent my web app from CSRF(Cross site request forgery) in java

查看:216
本文介绍了如何防止我的Web应用程序在Java中出现CSRF(跨站点请求伪造)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试阻止CSRF(跨站点请求伪造)
的Web应用程序,我点击了此链接 CSRF的链接

I am trying to prevent my web application from CSRF(Cross site request forgery) I followed this link Link for CSRF

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

This is what I have tried. To implement this mechanism in Java I choose to use two filters, one to create the salt for each request, and another to validate it. Since the users request and subsequent POST or GETs that should be validated do not necessarily get executed in order, I decided to use a time based cache to store a list of valid salt strings.

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

The first filter, used to generate a new salt for a request and store it in the cache can be coded as follows:

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() {

    }
}

在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>

在执行安全交易之前验证盐,我写了另一个过滤器:

to validate the salt before executing secure transactions I have written another filter:

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() {

    }

}

在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>

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

After configuring both servlets all your secured requests wasfailing :). To fix it you I had to add, to each link and form post that ends in a secure URL, the csrfPreventionSalt parameter containing the value of the request parameter with the same name. For example, in an HTML form within a JSP page:

<form action="/transferMoneyServlet" method="get">
    <input type="hidden" name="csrfPreventionSalt" value="<c:out value='${csrfPreventionSalt}'/>"/>
    ...
</form>

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

After doing all this I try to attempt CSRF, This what I did

<html>
<body>
<form action="http://localhost:8080/mywebapp/dispatcherServlet/addUserController/addUser" method="POST" enctype="text/plain">
<input type="hidden" name="&#123;&quot;userName&quot;&#58;&quot;CSRUser&quot;&#44;&quot;password&quot;&#58;&quot;CSRFUser123&quot;&#44;&quot;roles&quot;&#58;&quot;true&quot;&#44;&quot;status&quot;&#58;&quot;true&quot;&#125;" value="" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>

当我点击提交请求按钮时,我得到了一个成功的响应,
和CSRUser被添加到了数据库。

When I hit the submit request button , I got a success response, and CSRUser was added in my database.

我丢失了一些东西,如何防止CSRF攻击?

am I missing something, how do I prevent CSRF attack?

推荐答案

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

You can use Spring Security for users authentication and authorization. There is Cross Site Request Forgery (CSRF) support by default starting from Spring 3.2.0 version.

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

You can also easily exclude the URLs you do not want to protect by using RequestMatcher:

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);
}
}

来源

这篇关于如何防止我的Web应用程序在Java中出现CSRF(跨站点请求伪造)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆