En este artículo aprenderá cómo implementar una verificación CSRF en una extensión de Zimbra. El proyecto Java y el código fuente se pueden encontrar en https://github.com/Zimbra/zm-extension-guide .
En muchos casos, la política de recursos de origen cruzado en el navegador web y la configuración del atributo SameSite=Strict en la cookie de autenticación proporcionarán suficiente seguridad para su extensión. Sin embargo, en algunos casos, es posible que desee implementar una verificación CSRF adicional en su extensión. Por ejemplo, es posible que desee permitir la publicación de formularios HTTP solo desde un dominio específico en su organización (y no permitir subdominios).
Aquí hay una implementación de ejemplo:
/**n * Processes HTTP OPTIONS requests.n *n * Here is an example CSRF implementation, you may not need it for your application, also be aware of the following setting:n * zmlocalconfig -e zimbra_same_site_cookie="Strict"n *n * In this demonstration case the CSRF check is implemented on the HTTP Options request, in reality you would probably implement it on HTTP Post and Get.n *n * You will also need to set zimbraCsrfAllowedRefererHosts if you want to implement a referer check:n * zmprov mcf +zimbraCsrfAllowedRefererHosts "zimbra.example.com"n *n * Example request to test this CSRF implementation:n * curl 'https://zimbra.example.com/service/extension/mytest' -X OPTIONS -H 'X-Zimbra-Csrf-Token: 0_3278....030b' -H 'Referer: https://zimbra.example.com/modern/email/Inbox/conversation/266' -H 'Cookie: ZM_AUTH_TOKEN=0_78fe8e....a313b;'n *n * @param req request messagen * @param resp response messagen * @throws java.io.IOExceptionn * @throws javax.servlet.ServletExceptionn */nn @Overriden public void doOptions(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {n //all authentication is done by AuthUtil.getAuthTokenFromHttpReq, returns null if unauthorizedn final AuthToken authToken = AuthUtil.getAuthTokenFromHttpReq(req, resp, false, true);n if (authToken == null) {n resp.getOutputStream().print("No or invalid Auth token received.");n return;n }n String csrfToken = req.getHeader(Constants.CSRF_TOKEN);n if (!StringUtil.isNullOrEmpty(csrfToken)) {n resp.getOutputStream().print("No CSRF token received.");n return;n }nn //check for valid CSRF tokenn if (!CsrfUtil.isValidCsrfToken(csrfToken, authToken)) {n resp.getOutputStream().print("CSRF check FAILED.");n return;n }nn //do a CSRF referrer checkn String[] allowedRefHosts = null;n Provisioning prov = Provisioning.getInstance();n try {n allowedRefHosts = prov.getConfig().getCsrfAllowedRefererHosts();n } catch (Exception e) {n resp.getOutputStream().print("getCsrfAllowedRefererHosts failed.");n return;n }nn if (isValidCsrfReferrer(req, allowedRefHosts)) {n resp.getOutputStream().print("All CSRF checks passed.");n //Add your code heren } else {n resp.getOutputStream().print("CSRF referrer checks FAIL.");n }n }nnn public static boolean isValidCsrfReferrer(final HttpServletRequest req, final String[] allowedRefHost) {n List allowedRefHostList = Arrays.asList(allowedRefHost);n String referrer = req.getHeader(HttpHeaders.REFERER);n String refHost = null;nn URL refURL = null;n try {n refURL = new URL(referrer);n } catch (Exception e) {n return false;n }n refHost = refURL.getHost().toLowerCase();nn return allowedRefHost != null && allowedRefHostList.contains(refHost);n }