Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@joshdurbin
Created September 16, 2013 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save joshdurbin/6581142 to your computer and use it in GitHub Desktop.
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…
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
}
}
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)
}
}
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