Implement flood management with redis

I am trying to replace the Drupal 8 flow control sql implementation with a redis-based implementation.

See https://github.com/drupal/drupal/blob/8.0.x/core/lib/Drupal/Core/Flood/DatabaseBackend.php

The requirements are as follows:

  • Each action / event event (for example, a login attempt) is logged with an expiration date, ID and timestamp
  • I need to be able to prevent that a certain action can be done more than N times in a given period of time
  • I want to clean up past events
  • In the case of the threshold value 3 after 10 minutes, if the user tries once, and then twice after 5 minutes, he is blocked and can try again once after 5 minutes. Not 10. Although the second will be the right way to do this, this is not how the sql implementation works, or how the tests expect it to work.
  • As you can see based on the API, I also don’t know when I register an event, what is the threshold, I only know the expiration of one event.

My thoughts on how to implement this:

  • If after N occurrences is blocked for a given time, it will be easy with one key for the event: an identifier that increases after reaching a maximum, it is blocked until it expires again, and each INCR will also update its expiration date ( or not).
  • I found many posts that ask about the expiration of entries in the list, which is impossible. There are workarounds using sorted sets and range removal. Most seem to use the same global set, but I cannot easily calculate my event id +. I think.

After writing all this, I could have an idea of ​​how it might work, so I guess what I'm looking for is feedback about whether it makes sense or is there an easier way.

Each event: a combination of identifiers is a key and contains a sorted set. This uses the expiration as an estimate and as a value a unique value, possibly the creation time in microseconds. I am counting inexhaustible records to determine if a threshold has been reached. I update the expiration of each event: the identifier until the expiration window is provided, so it will be automatically deleted under the assumption that this identifier / client does not give up and continues to try before the expiration date. Is it worth it to clear records inside a set, for example. when creating a new register? It seems pretty fast, and I could sometimes do it sometimes.

+5
source share
1 answer

I would rather use the Redis expiration function, rather than overriding it.

A simpler alternative would be the following:

  • just set a simple value that represents the number of attempts; use a key built on a template of type "identifier": "event type": SETNX <identifier>:<event type> 1
  • if the answer is 1, this is the first attempt, so you set a timeout on this key: EXPIRE <identifier>:<event type> <timeout in seconds>

  • otherwise, you increase the number of attempts INCR <identifier>:<event type> The INCR response will give you the number of attempts during the window, so you know whether you can enable the action or not.

You can also use a hash instead of a simple value if you need to store more data, for example, the maximum number of allowed attempts in a given time window. In this case, you are likely to use HSETNX and HINCR.

+1
source

Source: https://habr.com/ru/post/1239523/


All Articles