springspring-bootsecuritynonceapi-security

Spring Boot API how to validate NONCE value sent in request header to avoid replay attacks


I have a Spring Boot application with custom authentication. I am intercepting the API requests using Servlet Filter and validating the request token sent. I am also requesting Nonce in request header from client which is a unique value sent from client in every API call.

I wanted to know if there is a standard way of checking Nonce received in header. I want to avoid replay attacks using Nonce.

One implementation I can think of is - store Nonce received in requests for 1 minute / maintain LRU cache of 100 requests in memory and make sure its not received again.

It would be helpful if you can point me to some good resources out there for good way of checking Nonce.

MySecurityFilter

@Component
@Order(1)
public class MySecurityFilter implements Filter {

    private static final Logger LOGGER = LoggerFactory.getLogger(MySecurityFilter.class);
    private static final String NONCE_PARAMETER_NAME = "x-nonce";

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        String nonce = getHeaderValue(req, NONCE_PARAMETER_NAME);
                
        //TODO: Validate Nonce

        chain.doFilter(request, response); 
    }
    //...
 }

PS: I am not using Spring security for API validation as its not required in my usecase.


Solution

  • Check below InMemoryNonceServices, which helps with sample implementation.

    https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth/src/main/java/org/springframework/security/oauth/provider/nonce/InMemoryNonceServices.java

    Ideally nonce are validated along with the request timestamp, hence you can simply reject the request with timestamp older than configured interval.

    Persistence of NONCE depends on your infra as well. If you are using IMDG like hazelcast/infispin or any other caching within your infra you can leverage them for persistence and TTL for the nonce.

    With DB, you may have to write a custom TTL solution which could be as simple as checking created timestamp against current time.

    Eg. : You could run scheduled cron-job to schedule simple DELETE commands or use pgAgent for the purpose in case of Postgres DB.

    Cloud data store such as AWS Dynamo DB provides TTL as well, but may not delete the data precisely at the expiry time.