为了防止CSRF,我遵循的步骤如下:
1.当请求到达(对于loginfilter)会话为空时,首先使用setAttribute()为此新会话创建会话添加令牌(randome编号),并使用dispatcher.forward重定向到login.jsp屏幕。
2.在login.jsp屏幕中使用getAttribute()将令牌存储在隐藏字段中。
3.在提交login.jsp时,第一个请求将来到loginfilter,这里将来自请求的令牌与会话中的令牌进行比较,如果匹配则继续执行动作类。否则为同一会话生成新令牌并使用sendRedirect()重定向到login.jsp
当我在这个应用程序上运行安全工具时,我的消息说“缺少一次令牌参数”。
请帮我。
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>
z.veb.hml
<?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);
}
}
在重定向时,只需指示浏览器向login.jsp发出新请求。此登录页面不会在隐藏字段中设置令牌,除非您使用的某些框架可以帮助您。所以改为使用请求调度程序。你还提到你运行了一个安全工具。如果它是模仿请求的工具,那么请确保在重播第二个请求中包含令牌,否则将无法识别。
编辑(代码发布后):我没有得到使用监听器的原因。您想要实现的是,无论何时创建会话,您都会自动将令牌与其关联。您也可以在过滤器类中执行此操作。请注意,httpRequest.getSession会检查会话,如果不存在,它也会创建。此方法的其他变体采用布尔参数。此外,您需要了解当您执行chain.doFilter(请求,响应)时,它意味着请求处理在链中继续进行。