Created
September 16, 2013 14:08
-
-
Save joshdurbin/6581142 to your computer and use it in GitHub Desktop.
The Excessive Selector Removal Filter is aimed at increasing security for sling/CQ/AEM instances with specific focus on selector-based denial-of-service attacks. The filter examines incoming, resource-based requests, looking for servlets that are registered for said resource. The filter will then build a list of the potential selectors and compa…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.citytechinc.services.selectorverification | |
import org.apache.felix.scr.annotations.Activate | |
import org.apache.felix.scr.annotations.Component | |
import org.apache.felix.scr.annotations.ConfigurationPolicy | |
import org.apache.felix.scr.annotations.Modified | |
import org.apache.felix.scr.annotations.Property | |
import org.apache.felix.scr.annotations.Service | |
import org.apache.sling.commons.osgi.OsgiUtil | |
@Service | |
@Component(label = 'Selector Override Definition', description = 'These definitions are read by the ExcessiveSelectorRemovalFilter. They allow specification if literal and wildcard selectors that might be used by non-servlets and services.', configurationFactory = true, policy = ConfigurationPolicy.REQUIRE, metatype = true) | |
class DefaultSelectorOverrideDefinition implements SelectorOverrideDefinition { | |
@Property(label = 'Selector', value = '', description = 'The valid selector') | |
private static final String SELECTOR_PROPERTY = 'selector' | |
private String selector | |
@Property(label = 'Assignment Indicator', value = '', description = 'The valid assignment indicator. If none is supplied, the selector is matched completely.') | |
private static final String ASSIGNMENT_INDICATOR_PROPERTY = 'assignmentIndicator' | |
private String assignmentIndicator | |
@Property(label = 'Resource Types', value = ['', ''], description = '') | |
private static final String RESOURCE_TYPES_PROPERTY = 'resourceTypes' | |
private String[] resourceTypes | |
@Activate | |
@Modified | |
protected void activate(Map<String, Object> properties) throws Exception { | |
selector = OsgiUtil.toString(properties.get(SELECTOR_PROPERTY), '') | |
assignmentIndicator = OsgiUtil.toString(properties.get(ASSIGNMENT_INDICATOR_PROPERTY), '') | |
resourceTypes = OsgiUtil.toStringArray(properties.get(RESOURCE_TYPES_PROPERTY), '') | |
} | |
@Override | |
String getSelector() { | |
selector | |
} | |
@Override | |
String getAssignmentIndicator() { | |
assignmentIndicator | |
} | |
@Override | |
List<String> getResourceTypes() { | |
resourceTypes | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.citytechinc.services.selectorverification | |
import com.google.common.collect.Lists | |
import groovy.util.logging.Slf4j | |
import org.apache.felix.scr.ScrService | |
import org.apache.felix.scr.annotations.Component | |
import org.apache.felix.scr.annotations.ConfigurationPolicy | |
import org.apache.felix.scr.annotations.Reference | |
import org.apache.felix.scr.annotations.ReferenceCardinality | |
import org.apache.felix.scr.annotations.ReferencePolicy | |
import org.apache.felix.scr.annotations.sling.SlingFilter | |
import org.apache.sling.api.SlingHttpServletRequest | |
import org.apache.sling.api.SlingHttpServletResponse | |
import javax.servlet.Filter | |
import javax.servlet.FilterChain | |
import javax.servlet.FilterConfig | |
import javax.servlet.Servlet | |
import javax.servlet.ServletException | |
import javax.servlet.ServletRequest | |
import javax.servlet.ServletResponse | |
@SlingFilter(order = -1000, generateComponent = false) | |
@Component(policy = ConfigurationPolicy.REQUIRE) | |
@Slf4j | |
class ExcessiveSelectorRemovalFilter implements Filter { | |
static final SLING_SERVLET_RESOURCE_TYPES_CONFIG_KEY = 'sling.servlet.resourceTypes' | |
static final SLING_SERVLET_SELECTORS_CONFIG_KEY = 'sling.servlet.selectors' | |
@Reference(cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC, referenceInterface = SelectorOverrideDefinition, bind = "bindOverride", unbind = "unbindOverride") | |
private List<SelectorOverrideDefinition> overrides = Lists.newCopyOnWriteArrayList() | |
@Reference | |
private ScrService scrService | |
@Override | |
void init(FilterConfig filterConfig) throws ServletException { | |
} | |
@Override | |
void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { | |
def slingRequest = servletRequest as SlingHttpServletRequest | |
def slingResponse = servletResponse as SlingHttpServletResponse | |
def requestSelectors = slingRequest.requestPathInfo.selectors as List<String> | |
def requestResourceType = slingRequest.resource?.resourceType | |
def matchingResourceSelectors = [] | |
overrides.each { override -> | |
if (override.resourceTypes.contains(requestResourceType)) { | |
if (override.assignmentIndicator) { | |
matchingResourceSelectors.addAll(requestSelectors.findAll { selector -> selector.startsWith(override.selector + override.assignmentIndicator)}) | |
} else { | |
matchingResourceSelectors.add(override.selector) | |
} | |
} | |
} | |
scrService.components.findAll { it.services?.contains(Servlet.name) }.each { | |
def resourceTypes = it.properties[SLING_SERVLET_RESOURCE_TYPES_CONFIG_KEY] as String | |
if (resourceTypes) { | |
def splitResourceTypes = resourceTypes.minus('[').minus(']').minus(' ').split(',') | |
if (splitResourceTypes.contains(requestResourceType)) { | |
def serviceSelectors = it.properties[SLING_SERVLET_SELECTORS_CONFIG_KEY] as String | |
if (serviceSelectors) { | |
def splitServiceSelectors = serviceSelectors.minus('[').minus(']').minus(' ').split(',') | |
matchingResourceSelectors.addAll(splitServiceSelectors) | |
} | |
} | |
} | |
} | |
def uniqueMatchingResourceSelectors = matchingResourceSelectors.unique() | |
def uniqueRequestSelectors = requestSelectors.unique() | |
def verifiedSelectors = uniqueRequestSelectors.intersect uniqueMatchingResourceSelectors | |
def unverifiedSelectors = uniqueRequestSelectors - verifiedSelectors | |
if (unverifiedSelectors) { | |
log.debug 'sending 404...' | |
slingResponse.sendError 404 | |
} else { | |
log.debug 'no excessive selectors found...' | |
filterChain.doFilter(servletRequest, servletResponse) | |
} | |
} | |
@Override | |
void destroy() { | |
} | |
protected void bindOverride(SelectorOverrideDefinition definition) { | |
overrides.add(definition) | |
} | |
protected void unbindOverride(SelectorOverrideDefinition definition) { | |
overrides.remove(definition) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.citytechinc.services.selectorverification | |
public interface SelectorOverrideDefinition { | |
String getSelector() | |
String getAssignmentIndicator() | |
List<String> getResourceTypes() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment