Expand my Community achievements bar.

Guidelines for the Responsible Use of Generative AI in the Experience Cloud Community.
SOLVED

content insight servlet

Avatar

Level 2

Hi Experts,

Can anyone help me understand the purpose of the below servlet and what it is used for?

http://localhost:4502/libs/cq/contentinsight/proxy/reportingservices.json.GET.servlet.a.23.css

Our team reported a vulnerability that using this servlet they can perform SSRF attacks and reach to the publisher bypassing the dispatcher.

While restricting it is an immediate measure we have taken but would like to understand the impact of restricting at the dispatcher.

Any inputs or links referring to the original documentation would be of great help

Regards

Kartheek

1 Accepted Solution

Avatar

Correct answer by
Employee

Hi Kartheek,

Apologies for the delay, I was confirming if the information is fine to release to public.

The workaround instead of installing the patch is to:

Change the “Whitelist” value from .*/api[0-9]*.omniture.com/.*  to https?:\/\/api(\d+)?\.omniture\.com(:\d+)?\/rs\/0\.5\/.* within /system/console/configMgr/com.adobe.cq.contentinsight.impl.servlets.ReportingServicesProxyServlet configuration.

Please make sure to upgrade to latest official patch when possible.

Regards,

Lisa

View solution in original post

9 Replies

Avatar

Employee

Hi Kartheek,

The purpose of the ReportingServicesProxyServlet.java servlet (found in the notes directly in the source code):

/**
* A servlet that proxies requests to Reporting Services's API for browsers
* not supporting real CORS, i.e. IE 9 with XDomainRequest.
* <p>
* The API's response code and body are copied to the servlet response.
*/

This SSRF vulnerability is related to Adobe Security Bulletin

Please note that the immediate fix would be to install the corresponding hotfix for your AEM version (if the official patch has not been released yet).

Proactive HF for 6.0 - https://www.adobeaemcloud.com/content/marketplace/marketplaceProxy.html?packagePath=/content/compani... 

Proactive HF for 6.1 - https://www.adobeaemcloud.com/content/marketplace/marketplaceProxy.html?packagePath=/content/compani...

Pro-active HF for 6.2 - https://www.adobeaemcloud.com/content/marketplace/marketplaceProxy.html?packagePath=/content/compani...

Pro-active HF for 6.3 - https://www.adobeaemcloud.com/content/marketplace/marketplaceProxy.html?packagePath=/content/compani...

Pro-active HF for 6.4 - https://www.adobeaemcloud.com/content/marketplace/marketplaceProxy.html?packagePath=/content/compani...

Regards,

Lisa

Avatar

Community Advisor

kartheekd20304289​ The servlet which invoked in backend of mentioned URL (http://localhost:4502/libs/cq/contentinsight/proxy/reportingservices.json.GET.servlet.a.23.css ) is ReportingServicesProxyServlet.java.

For more info, you can have a look at the code.

package com.adobe.cq.contentinsight.impl.servlets;

import org.slf4j.LoggerFactory;

import org.apache.felix.scr.annotations.Activate;

import org.apache.sling.commons.osgi.PropertiesUtil;

import org.osgi.service.component.ComponentContext;

import java.util.regex.Pattern;

import java.io.IOException;

import javax.servlet.ServletException;

import org.apache.http.HttpResponse;

import org.apache.http.impl.client.CloseableHttpClient;

import org.apache.http.client.HttpClient;

import java.net.URISyntaxException;

import org.apache.http.client.utils.HttpClientUtils;

import java.io.OutputStream;

import org.apache.commons.io.IOUtils;

import org.apache.http.client.methods.HttpUriRequest;

import org.apache.http.client.methods.HttpGet;

import org.apache.http.client.utils.URIBuilder;

import org.apache.sling.api.SlingHttpServletResponse;

import org.apache.sling.api.SlingHttpServletRequest;

import org.slf4j.Logger;

import org.apache.felix.scr.annotations.Reference;

import org.apache.http.osgi.services.HttpClientBuilderFactory;

import org.apache.felix.scr.annotations.Property;

import org.apache.felix.scr.annotations.sling.SlingServlet;

import org.apache.sling.api.servlets.SlingSafeMethodsServlet;

@SlingServlet(generateComponent = true, metatype = true, resourceTypes = { "cq/contentinsight/proxy" }, extensions = { "json" }, selectors = { "reportingservices" }, methods = { "GET" }, label = "Reporting Services API proxy servlet", description = "Proxy servlet for Reporting Services API")

public class ReportingServicesProxyServlet extends SlingSafeMethodsServlet

{

    private static final String DEFAULT_API_OMNITURE_URL = ".*/api[0-9]*.omniture.com/.*";

    @Property(name = "reportingservices.proxy.whitelist", label = "Whitelist", description = "Allowed destinations for the reporting services proxy servlet", cardinality = Integer.MAX_VALUE, value = { ".*/api[0-9]*.omniture.com/.*" })

    private String[] whiteList;

    @Reference

    private HttpClientBuilderFactory clientBuilderFactory;

    private static final long serialVersionUID = 7044811756109092040L;

    private static final Logger LOG;

   

    public ReportingServicesProxyServlet() {

        this.whiteList = new String[] { ".*/api[0-9]*.omniture.com/.*" };

    }

   

    protected void doGet(final SlingHttpServletRequest request, final SlingHttpServletResponse response) throws ServletException, IOException {

        final String url = request.getParameter("url");

        final String query = request.getParameter("q");

        if (url == null || query == null) {

            response.setStatus(400);

            return;

        }

        if (!this.isUrlAllowed(url)) {

            ReportingServicesProxyServlet.LOG.warn("Received url " + url + " not whitelisted!");

            return;

        }

        final CloseableHttpClient httpClient = this.clientBuilderFactory.newBuilder().build();

        try {

            final URIBuilder uriBuilder = new URIBuilder(url);

            uriBuilder.addParameter("q", query);

            final HttpGet get = new HttpGet(uriBuilder.build());

            get.setHeader("x-adobe-rs-auth", request.getHeader("x-adobe-rs-auth"));

            HttpResponse getResponse = null;

            try {

                getResponse = (HttpResponse)httpClient.execute((HttpUriRequest)get);

                final int status = getResponse.getStatusLine().getStatusCode();

                IOUtils.copy(getResponse.getEntity().getContent(), (OutputStream)response.getOutputStream());

                response.setStatus(status);

            }

            finally {

                HttpClientUtils.closeQuietly(getResponse);

            }

        }

        catch (URISyntaxException e) {

            ReportingServicesProxyServlet.LOG.error("Invalid URL: " + url, (Throwable)e);

        }

        finally {

            HttpClientUtils.closeQuietly((HttpClient)httpClient);

        }

    }

   

    private boolean isUrlAllowed(final String url) {

        boolean isAllowed = false;

        for (final String whitelistedRegex : this.whiteList) {

            final Pattern pattern = Pattern.compile(whitelistedRegex);

            isAllowed = pattern.matcher((CharSequence)url).matches();

            if (isAllowed) {

                break;

            }

        }

        return isAllowed;

    }

   

    @Activate

    protected void activate(final ComponentContext ctx) {

        this.whiteList = PropertiesUtil.toStringArray(ctx.getProperties().get("reportingservices.proxy.whitelist"), new String[] { ".*/api[0-9]*.omniture.com/.*" });

    }

   

    static {

        LOG = LoggerFactory.getLogger((Class)ReportingServicesProxyServlet.class);

    }

   

    protected void bindClientBuilderFactory(final HttpClientBuilderFactory clientBuilderFactory) {

        this.clientBuilderFactory = clientBuilderFactory;

    }

   

    protected void unbindClientBuilderFactory(final HttpClientBuilderFactory httpClientBuilderFactory) {

        if (this.clientBuilderFactory == httpClientBuilderFactory) {

            this.clientBuilderFactory = null;

        }

    }

}

Avatar

Employee

kartheekd20304289​ , yes , http://localhost:4502/libs/cq/contentinsight/proxy/reportingservices.json.GET.servlet.a.23 .css is the same as ReportingServicesProxyServlet.java servlet .

Here is better description regarding the functionality of this servlet:

The servlet is proxying requests for browsers (older IE) that do not properly support CORS XMLHttpRequests. The servlet is not used if Content-Insight is used with modern browsers.

Applying a Dispatcher filter would indeed interfere with the Content-Insight feature as other functionality is also exposed at /libs/cq/contentinsight/content/*.  However, we suggest to go with the official patch / hotfix to resolve the issue.

Avatar

Level 2

Thanks.

Can you please share the appropriate hotfix/patch package for AEM Version 6.3.1.2

Avatar

Employee

Hi kartheekd20304289

The appropriate hotfix/patch package for AEM Version 6.3.1.2 is:

https://www.adobeaemcloud.com/content/marketplace/marketplaceProxy.html?packagePath=/content/compani...

Please note that the pre-requisite for this hotfix is SP2.

Regards,

Lisa

Avatar

Level 2

Hi Lisa,

Unfortunately we are not on SP2 and we cannot upgrade to SP2 within the next few days.

Is there a way to mitigate the upgrade and provide us with a specific patch for our version so we can fix the security vulnerability faster?

Avatar

Level 2

HI Lisa,

Please let us know  if there is any workaround without SP2 upgrade?

Avatar

Correct answer by
Employee

Hi Kartheek,

Apologies for the delay, I was confirming if the information is fine to release to public.

The workaround instead of installing the patch is to:

Change the “Whitelist” value from .*/api[0-9]*.omniture.com/.*  to https?:\/\/api(\d+)?\.omniture\.com(:\d+)?\/rs\/0\.5\/.* within /system/console/configMgr/com.adobe.cq.contentinsight.impl.servlets.ReportingServicesProxyServlet configuration.

Please make sure to upgrade to latest official patch when possible.

Regards,

Lisa