JSF 2.x has already builtin CSRF prevention in flavor of javax.faces.ViewState hidden field in the form when using server side state saving. In JSF 1.x this value was namely pretty weak and too easy predictable (it was actually never intended as CSRF prevention). In JSF 2.0 this has been improved by using a long and strong autogenerated value instead of a rather predictable sequence value and thus making it a robust CSRF prevention.
In JSF 2.2 this is even be further improved by making it a required part of the JSF specification, along with a configurable AES key to encrypt the client side state, in case client side state saving is enabled. New in JSF 2.2 is CSRF protection on GET requests by <protected-views>.
使用JSF 1.x的遗留代码,可以扩展form,在form内增加一个token,token通过SessionListener生成,保存在Session中,代码如下:
CsrfSessionListener
public class CsrfSessionListener implements HttpSessionListener { private static final String CSRF_TOKEN_NAME = "CsrfToken"; @Override public void sessionCreated(HttpSessionEvent se) { HttpSession session = se.getSession(); session.setAttribute(CSRF_TOKEN_NAME, UUID.randomUUID().toString()); } @Override public void sessionDestroyed(HttpSessionEvent se) { } }
CsrfForm
public class CsrfForm extends HtmlForm { private static final String CSRF_TOKEN_NAME = "CsrfToken"; private static final String CSRF_TOKEN_ID = "csrf_token"; @Override public void encodeEnd(FacesContext context) throws IOException { encodeCsrfTokenInput(context); super.encodeEnd(context); } private void encodeCsrfTokenInput(FacesContext context) throws IOException { ResponseWriter responseWriter = context.getResponseWriter(); responseWriter.startElement("input", null); responseWriter.writeAttribute("type", "hidden", null); responseWriter.writeAttribute("id", getCsrfInputClientId(context), null); responseWriter.writeAttribute("name", CSRF_TOKEN_ID, null); responseWriter.writeAttribute("value", getToken(context), "value"); responseWriter.endElement("input"); } @Override public void decode(FacesContext context) { Map<String, String> requestMap = context.getExternalContext().getRequestParameterMap(); String value = requestMap.get(CSRF_TOKEN_ID); // check if the token exists if (value == null || "null".equals(value) || "".equals(value)) { throw new CsrfException("CSRFToken is missing!"); } String token = getToken(context); // check the values for equality if (!value.equalsIgnoreCase(token)) { throw new CsrfException("CSRFToken does not match!"); } super.decode(context); } private String getCsrfInputClientId(FacesContext context) { return getClientId(context) + ":" + CSRF_TOKEN_ID; } private String getToken(FacesContext context) { HttpSession session = (HttpSession) context.getExternalContext().getSession(false); return (String) session.getAttribute(CSRF_TOKEN_NAME); } }
CsrfException
public class CsrfException extends RuntimeException { public CsrfException(String message) { super(message); } }
然后在faces-config.xml中增加配置,使用CsrfForm:
<component> <component-type>javax.faces.HtmlForm</component-type> <component-class>org.iata.csrf.CsrfForm</component-class> </component>
验证Referer
登录后将host保存在Session中
session.setAttribute("HOST", req.getHeader("host"));
然后在filter中验证:
package org.iata.csrf; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; public class CsrfFilter implements Filter { private static final String HTTP = "http://"; private static final String HTTPS = "https://"; private static final String REGEX = "https://|http://"; @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; HttpSession session = req.getSession(false); String host = (String) session.getAttribute("HOST"); String referer = req.getHeader("Referer"); if (referer == null) { chain.doFilter(request, response); return; } if (referer.startsWith(HTTP) || referer.startsWith(HTTPS)) { referer = referer.replaceFirst(REGEX, ""); } if (referer.startsWith(host)) { chain.doFilter(request, response); return; } res.sendRedirect(req.getContextPath() + "/NoAuthorityError.seam"); } @Override public void destroy() { } }
相关推荐
jboss-ajax4jsf-1.1.1-src 具体自己看吧
这是jsf-api-2.0.jar,为了使用方便传上来.只是个jar包.
参考合同-集体林权流转合同(JSF-2015-2602).zip
jsf-api-1.2帮助文档。。
航空系统C++软件开发规范,此规范的目的是确保编出的代码满足安全、可靠、可测试和已维护的特点。
合同模板协议范文2021江苏省商品交易市场设施租赁、管理服务合同(JSF-2008-0601).docx
jsf-impl-2.0.0源代码文件, jsf-impl-2.0.0-SNAPSHOT-sources.jar
这是jsf-impl-1.2_15.jar,为了使用方便传上来.只是个jar包.
JSF-api-1.2_14-sources.jar,提供了jsf使用时的多种内部类。
jsf-spring-4.0.3 jsf他spring结合的工具,from :sorseforce
jsf-api-1.2-12.jar
JavaEE源代码 jsf-apiJavaEE源代码 jsf-apiJavaEE源代码 jsf-apiJavaEE源代码 jsf-apiJavaEE源代码 jsf-apiJavaEE源代码 jsf-apiJavaEE源代码 jsf-apiJavaEE源代码 jsf-apiJavaEE源代码 jsf-apiJavaEE源代码 jsf-...
JSF-2-Hello-World-Example.zip
jsf-by-example-源码.rar
JavaEE源代码 jsf-implJavaEE源代码 jsf-implJavaEE源代码 jsf-implJavaEE源代码 jsf-implJavaEE源代码 jsf-implJavaEE源代码 jsf-implJavaEE源代码 jsf-implJavaEE源代码 jsf-implJavaEE源代码 jsf-implJavaEE源...
个人学习EJB-JSF-JPA-MINA 时用到的入门资料~ 适合初学者。 希望能帮到正在学习EJB、SF、JPA、MINA的初学者们。
jsf-api,jsf-impl,jst1-1.2,javaee是基于java的web开发,java ee5.0的jar 包汇总
java-ee-7-com-jsf-primefaces-e-cdi
tomcat里的jar 包,在项目启动时缺少包
javaee.jar,jsf-api.jar,jsf-impl.jar,jstl-1.2.jar