Home | content | failed-login-attempt-throttling-cas

Failed login attempt throttling in CAS

Part of a series on reviewing CAS configuration, this post discusses failed login attempt throttling in CAS.

CAS ships with handler interceptors suitable for throttling failed login attempts.

Adopters should consider whether and which throttling configured how would be appropriate for their CAS implementation.

There are three available concrete throttling implementations, as well as the abstract class support for building new implementations should none of the included options quite suit.

Choice of implementation depends on:

  • Is it sufficient to use in-memory per-CAS-server-node state about recent failed login attempts, or do you need it use potentially shared-across-CAS-server-nodes Inspektr audit trail state?
  • Is remote address an appropriate criteria for throttling?
  • Is username and appropriate criteria for throttling?

Considering IP address only, in-memory

The InMemoryThrottledSubmissionByIpAddressHandlerInterceptorAdapter considers the REMOTE_ADDRESSonly in watching failed login attempts over time and blocks additional login attempts once the too-many-recent-failures threshold is reached.

This implementation is useful for throttling attacks with few login attempts per account spread across many accounts, e.g., attacks looking for accounts using one of a few likely passwords. (“Tr0ub4dor&3”?) Backing credentials stores that throttle are typically ill-equipped to block this sort of attack, since all credentials validation requests appear to come from the same remote address (CAS!) from the perspective of the credentials store regardless of whether all these failures are coming to CAS from the same place out in the Internet.

Since this implementation uses an in-memory map to track failed login attempts, it does not share state across CAS server nodes and individual CAS server nodes will need to saturate independently to start blocking login attempts meeting the threshold criteria. This per-CAS-server-node approach to thresholding is usually fine.

Considering IP address and username, in memory

The InMemoryThrottledSubmissionByIpAddressAndUsernameHandlerInterceptorAdapter considers the REMOTE_ADDRESSand the end-user-asserted username in watching failed login attempts over time and blocks attempts for a given IP address and username pair after a threshold of failure load has been reached.

Considering IP address and username as logged to RBDMS-backed Inspektr audit trail

Like the InMemoryThrottledSubmissionByIpAddressAndUsernameHandlerInterceptorAdapter, the InspektrThrottledSubmissionByIpAddressAndUsernameHandlerInterceptorAdapter considers the REMOTE_ADDRESSand end-user-asserted username in watching failed login attempts over time and block attempts for a given IP address and username pair after a threshold of failure load is reached. Rather than storing failure in-memory, it relies on the Inspektr audit trail record of failed login attempts and logs throttled login attempts to the audit trail log.

This throttling implementation depends on the database-backed implementation of Inspektr audit trail logging.

Configuring failed login attempt throttling

Does throttling at the CAS layer add value?

Throttling in the CAS layer can add value when the backing credential store isn’t throttling or when more context is available to CAS to inform throttling.

For instance, if the backing credential layer doesn’t throttle at all, throttling at the CAS layer may be the only option for preventing brute force attacks against account passwords.

If the backing credential layer throttles per-account, the CAS layer might nonetheless have a throttling role to play in throttling on criteria not available to the backing credential layer, i.e. based on the IP address appearing to make too frequent failed login attempts.

On suitability of using REMOTE_ADDRESS

Considering the remote address in throttling requires that the remote address of the request is faithfully conveyed through the network, hardware, and software stack in front of the CAS web application such that the perceived REMOTE_ADDRESSreflects the network location of the end user making the request of CAS. In situations where CAS is fronted by a proxy such that all requests appear to come from the same REMOTE_ADDRESS, using remote address as the only factor for throttling will result in inadvertently triggering the throttling mechanism in consideration of login failures from multiple users. In such a cause using remote address as one of several factors for throttling renders the remote address part of it meaningless. In short, remote address as a factor in failed login attempt throttling makes sense only when remote address as perceived by the CAS server reflects the network address of the requesting end user.

Where this is configured

These are all interceptors that are painted on to the Spring Web Flow Handler.

in /WEB-INF/cas-servlet.xml, edit

<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping" 
    p:flowRegistry-ref="flowRegistry"
    p:order="2">
  <property name="interceptors">
    <ref local="localeChangeInterceptor"/>
  </property>
</bean>

to declare the additional interceptor, i.e.:

<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping" 
               p:flowRegistry-ref="flowRegistry" p:order="2">
  <property name="interceptors">
    <list>
        <ref local="localeChangeInterceptor"/>
        <ref bean="throttleInterceptor"/>
    </list>
  </property>
</bean>

And add an XML file to /WEB-INF/spring-configuration/declaring the desired interceptor, as in

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:p="http://www.springframework.org/schema/p"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

<bean id="throttleInterceptor" class="org.jasig.cas.web.support.InMemoryThrottledSubmissionByIpAddressAndUsernameHandlerInterceptorAdapter" />

<bean id="throttleInterceptorJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"
   p:targetObject-ref="throttleInterceptor"
   p:targetMethod="decrementCounts" />

<bean id="periodicThrottleCleanerTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"
 p:jobDetail-ref="throttleInterceptorJobDetail"
 p:startDelay="0"
 p:repeatInterval="1000" />
</beans>

This configuration is a little picky and difficult to understand. Unicon can assist with formulating sensible configuration to achieve desired throttling policy.

Return to the blog listing page