【发布时间】:2016-10-10 03:53:33
【问题描述】:
我正在尝试防止我的 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() {
}
}
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>
为了在执行安全交易之前验证盐,我编写了另一个过滤器:
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 参数。例如,在 JSP 页面内的 HTML 表单中:
<form action="/transferMoneyServlet" method="get">
<input type="hidden" name="csrfPreventionSalt" value="<c:out value='${csrfPreventionSalt}'/>"/>
...
</form>
做完这一切后,我尝试尝试 CSRF,这就是我所做的
<html>
<body>
<form action="http://localhost:8080/mywebapp/dispatcherServlet/addUserController/addUser" method="POST" enctype="text/plain">
<input type="hidden" name="{"userName":"CSRUser","password":"CSRFUser123","roles":"true","status":"true"}" value="" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>
当我点击提交请求按钮时,我得到了成功响应, 并且 CSRUser 已添加到我的数据库中。
我错过了什么,如何防止 CSRF 攻击?
【问题讨论】:
-
有用!它对我有帮助
标签: java csrf-protection