问题概述:
我们正在将我们的系统从CQ5.4升级到AEM 6.1。在现有的代码中,我们使用ajax引用了POST.jsp,在这里我们调用身份验证服务来向系统验证外部用户。当我们在error.log中对资源post.jsp进行ajax发布时,我们会得到以下错误。com.adobe.granite.csrf.impl.CSRFilter doFilter:提供的csrf令牌是无效的
我们尝试过什么:
- 为了解决这个问题,我们根据AEM 6.1文档尝试了解决方案https://docs.adobe.com/docs/en/aem/6-1/administer/security/security-checklist.html#par_title_1046104842.
但这并没有奏效 - 我们尝试从system/console/configMgr的Adobe Granite CSRF filter配置中的筛选器方法中删除POST。这起到了作用,但这影响了我们系统的安全性,因为它允许其他外部系统到POST数据。(如果我在安全方面说错了,请纠正我)
- 我们尝试从system/console/configMgr在Adobe Granite CSRF Filter配置中的安全用户代理中添加谷歌chrome浏览器用户代理。这起到了作用,但该应用程序可以从各种其他用户代理中使用,我们无法将其保留在安全用户代理的白名单中
此外,我们对com.adobe.granite.csrf.impl.CSRFFilter进行了反编译,并找到了以下代码:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain Chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
if ((request.getAuthType() != null) && (isFilteredMethod(request)) && (doFilterBasedOnUserAgent(request)) && (!isValidRequest(request))) {
HttpServletResponse response = (HttpServletResponse)res;
this.logger.info("doFilter: the provided CSRF token is invalid");
response.sendError(403);
return;
}
chain.doFilter(req, res);
}
在上述代码中,isFilteredMethod检查当前请求(POST)是否存在于Adobe Granite CSRF Filter的已配置过滤方法中
doFilterBasedOnUserAgent检查当前请求的用户代理在配置的用户代理中是否不存在
request.getAuthType在我们的例子中是"FORM"。因此,这不会导致(403)
isValidRequest获取请求参数:cq_csrf_token,并检查此参数值有效。(注意到这一点,在我们的案例中有效并发送参数)
那么,过滤方法和用户代理的意义是什么呢?为什么CSRF为POST.jsp发送403,尽管所有CQ和AEM5.x版本都支持这种方式的POSTING请求?
所以你可以做几件事-
- 将cq.jquery客户端库用于jquery,而不是手动创建并包含jquery库。aem提供的jquery有处理csrf令牌的代码
- 在代码中包含granite.csrf.standalone clientlib。它会为你做这些事情
- 您可以从/libs/agrante/csrf/token.json手动获取令牌的值。在csrf令牌头中的每个请求中都发送此值
或者,您可以在"Adobe Granite CSRF filter configuration"下过滤自己的servlet,而不是使用cq-jquery允许所有POST请求或以上请求。