001package org.apache.wiki.http.filter; 002 003import org.apache.logging.log4j.LogManager; 004import org.apache.logging.log4j.Logger; 005import org.apache.wiki.api.core.Engine; 006import org.apache.wiki.api.core.Session; 007import org.apache.wiki.api.spi.Wiki; 008 009import javax.servlet.Filter; 010import javax.servlet.FilterChain; 011import javax.servlet.FilterConfig; 012import javax.servlet.ServletException; 013import javax.servlet.ServletRequest; 014import javax.servlet.ServletResponse; 015import javax.servlet.http.HttpServletRequest; 016import javax.servlet.http.HttpServletResponse; 017import java.io.IOException; 018 019 020/** 021 * CSRF protection Filter which uses the synchronizer token pattern – an anti-CSRF token is created and stored in the 022 * user session and in a hidden field on subsequent form submits. At every submit the server checks the token from the 023 * session matches the one submitted from the form. 024 */ 025public class CsrfProtectionFilter implements Filter { 026 027 private static final Logger LOG = LogManager.getLogger( CsrfProtectionFilter.class ); 028 029 public static final String ANTICSRF_PARAM = "X-XSRF-TOKEN"; 030 031 /** {@inheritDoc} */ 032 @Override 033 public void init( final FilterConfig filterConfig ) { 034 } 035 036 /** {@inheritDoc} */ 037 @Override 038 public void doFilter( final ServletRequest request, final ServletResponse response, final FilterChain chain ) throws IOException, ServletException { 039 if( isPost( ( HttpServletRequest ) request ) ) { 040 final Engine engine = Wiki.engine().find( request.getServletContext(), null ); 041 final Session session = Wiki.session().find( engine, ( HttpServletRequest ) request ); 042 if( !requestContainsValidCsrfToken( request, session ) ) { 043 LOG.error( "Incorrect {} param with value '{}' received for {}", 044 ANTICSRF_PARAM, request.getParameter( ANTICSRF_PARAM ), ( ( HttpServletRequest ) request ).getPathInfo() ); 045 ( ( HttpServletResponse ) response ).sendRedirect( "/error/Forbidden.html" ); 046 return; 047 } 048 } 049 chain.doFilter( request, response ); 050 } 051 052 public static boolean isCsrfProtectedPost( final HttpServletRequest request ) { 053 if( isPost( request ) ) { 054 final Engine engine = Wiki.engine().find( request.getServletContext(), null ); 055 final Session session = Wiki.session().find( engine, request ); 056 return requestContainsValidCsrfToken( request, session ); 057 } 058 return false; 059 } 060 061 private static boolean requestContainsValidCsrfToken( final ServletRequest request, final Session session ) { 062 return session.antiCsrfToken().equals( request.getParameter( ANTICSRF_PARAM ) ); 063 } 064 065 static boolean isPost( final HttpServletRequest request ) { 066 return "POST".equalsIgnoreCase( request.getMethod() ); 067 } 068 069 /** {@inheritDoc} */ 070 @Override 071 public void destroy() { 072 } 073 074}