Expand my Community achievements bar.

SOLVED

CQ 5.5 - How to intercept submission of (OOTB) comment to validate before comment is posted

Avatar

Level 1

Hello,

I am using the out of the box comment component on CQ5.5 (upgraded from CQ5.4).  We recently had an issue in which the POST'd comment could be vulnerable to a CSRF (cross-site request forgery) attack.  So in order to prevent it, I need to include a CSRF token as part of the form submission, upon which a server-side check is done to confirm the validity of the token before the comment is allowed to be posted.

Since the comment POST is handled by an OOTB servlet, is there a way to intercept the Comment POST to validate the token before it is saved?

1 Accepted Solution

Avatar

Correct answer by
Level 7

Hi Chris.

One suggestion that came to my mind here is that you could make use of you own servlet filter.
If this servlet filter is arranged before the standard comment servlet in the chain this will be possible to intercept before the actual comment servlet.
If everything is fine with the token submitted then simply let the request pass through the chain of filters already there.

However, if something is wrong with it, or that the token is missing, then you will have to handle it accordingly..
This would somehow be equivalent of let say how a CAPTCHA filter would work. It would interpret the request before it is handled by the common comment servlet and validate a code that you have entered somewhere in the form. If the code is missing or wrong, it could simply redirect you to the form page with an optional notification.

There is a lot of information on how you create your own servlet filters so it should probably not be a problem to get you started on that :)

Edit:
Maybe something like this ?
 

@Component(immediate=true, metatype=false) @Service(value=javax.servlet.Filter.class) @Properties({ @Property(name="service.description", value="My Token Filter"), @Property(name="service.vendor", value="The Apache Software Foundation"), @Property(name="filter.scope", value="request"), @Property(name="sling.filter.scope", value="request"), @Property(name="pattern", value="/.*") //Add the required pattern here }) public class MyTokenFilter implements Filter { private static final Logger log = LoggerFactory.getLogger(com.mycompany.MyTokenFilter.class); public void init(FilterConfig filterConfig) throws ServletException { // nothing to do? } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = ((HttpServletRequest)request); HttpServletResponse res = ((HttpServletResponse)response); HttpSession session = req.getSession(); if (req.getParameter("userToken") != null){ log.debug("My Token:" + req.getParameter("userToken")); if (session != null){ log.debug("The token session is actually here!"); MyToken token = (Mytoken) session.getAttribute("token"); log.debug("Token generated by the session:" + token.toString()); if (token != null){ if (token.isSame(req.getParameter("userToken"))) { log.debug("Oh no, something is wrong. Redirect ?"); return; }else{ //Well that went allright, then just dont do that much and let the request pass thorugh log.debug("Nice, token is correct, maybe set some acc message..."); } }else{ log.debug("There is no token ?!?! ABORT!"); } } } chain.doFilter(request, response); } public void destroy() { } }





Regards
Johan

 

View solution in original post

1 Reply

Avatar

Correct answer by
Level 7

Hi Chris.

One suggestion that came to my mind here is that you could make use of you own servlet filter.
If this servlet filter is arranged before the standard comment servlet in the chain this will be possible to intercept before the actual comment servlet.
If everything is fine with the token submitted then simply let the request pass through the chain of filters already there.

However, if something is wrong with it, or that the token is missing, then you will have to handle it accordingly..
This would somehow be equivalent of let say how a CAPTCHA filter would work. It would interpret the request before it is handled by the common comment servlet and validate a code that you have entered somewhere in the form. If the code is missing or wrong, it could simply redirect you to the form page with an optional notification.

There is a lot of information on how you create your own servlet filters so it should probably not be a problem to get you started on that :)

Edit:
Maybe something like this ?
 

@Component(immediate=true, metatype=false) @Service(value=javax.servlet.Filter.class) @Properties({ @Property(name="service.description", value="My Token Filter"), @Property(name="service.vendor", value="The Apache Software Foundation"), @Property(name="filter.scope", value="request"), @Property(name="sling.filter.scope", value="request"), @Property(name="pattern", value="/.*") //Add the required pattern here }) public class MyTokenFilter implements Filter { private static final Logger log = LoggerFactory.getLogger(com.mycompany.MyTokenFilter.class); public void init(FilterConfig filterConfig) throws ServletException { // nothing to do? } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = ((HttpServletRequest)request); HttpServletResponse res = ((HttpServletResponse)response); HttpSession session = req.getSession(); if (req.getParameter("userToken") != null){ log.debug("My Token:" + req.getParameter("userToken")); if (session != null){ log.debug("The token session is actually here!"); MyToken token = (Mytoken) session.getAttribute("token"); log.debug("Token generated by the session:" + token.toString()); if (token != null){ if (token.isSame(req.getParameter("userToken"))) { log.debug("Oh no, something is wrong. Redirect ?"); return; }else{ //Well that went allright, then just dont do that much and let the request pass thorugh log.debug("Nice, token is correct, maybe set some acc message..."); } }else{ log.debug("There is no token ?!?! ABORT!"); } } } chain.doFilter(request, response); } public void destroy() { } }





Regards
Johan