Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.5] Request throttling #19807

Merged
merged 1 commit into from
Jul 2, 2017
Merged

[5.5] Request throttling #19807

merged 1 commit into from
Jul 2, 2017

Conversation

lucasmichot
Copy link
Contributor

@lucasmichot lucasmichot commented Jun 28, 2017

At the moment, the request throttling system allows to limit the number of request per route and IP.

This is not adapted to the following cases:

Unauthenticated mode

In this case this system would be very quickly inefficient to handle a dDOS, and a service like https://www.cloudflare.com would be a much more adapted and reliable solution.
Still we want to be able to provide this feature for guest users.

Authenticated mode

We want to identify the user by his ID, not his IP.

Authenticated mode with a different quota

We want to provide a different rate limit for authenticated user.

Per group (of routes) throttling

The throttling cannot handle a group of route as at the moment, the throttling that the route itself in consideration.

Conditional requests

In many services, to encourage users to use HTTP caching mechanism, an thus avoid workload on the server, the 304 responses don't count for a hit.

Content type compliant response

We might want to return a 429 response if the user has made too many attempts. We might also want to choose the content-type for this response (like application/json for an API response).
In this case, it seems better to throw an exception instead of returning a response. The exception can be later tweaked in the application Exception handler, if necessary.


TODO:

  • If the user is authenticated, generate the signature from his ID.
  • If the user is unauthenticated, generate the signature from the application domain and the client IP.
  • If the user is authenticated, give the possibility to provide a different quota and/or a different duration
  • Move the signature generation to the middleware.

Usage

// 5000 req./hr for any user
'throttle:5000,60',

// 99 req./hr for guests, 5000 req./hr for authenticated users
'throttle:99|5000,60',

@lucasmichot lucasmichot changed the title [5.5] WIP - Request throttling [5.5] Request throttling Jun 29, 2017
@lucasmichot lucasmichot changed the title [5.5] Request throttling [5.5] [WIP] Request throttling Jun 29, 2017
@lucasmichot lucasmichot changed the title [5.5] [WIP] Request throttling [5.5] Request throttling Jun 29, 2017

$maxAttempts = explode('|', $maxAttempts, 2);

return $maxAttempts[(int) $request->user()];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't it be $maxAttempts[$request->user() ? 1 : 0] ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I was using it the other way around. Thx

@lucasmichot lucasmichot changed the title [5.5] Request throttling [5.5] [WIP] Request throttling Jun 30, 2017
@taylorotwell
Copy link
Member

I don't want this skipNotModified option. It makes the actual attaching of the middleware unintelligible.

@lucasmichot lucasmichot changed the title [5.5] [WIP] Request throttling [5.5] Request throttling Jul 1, 2017
@carduz
Copy link

carduz commented Jan 12, 2018

Hi,

I have seen in resolveRequestSignature you have removed $request->fingerprint(), this means that if the user is logged all requests (with different routes) has the same key: sha1($user->getAuthIdentifier()).
I think that this is a big issue: if you want to restrict some routes you cannot, since the rate limit counter is in common.

Regards

@trevorgehman
Copy link
Contributor

Just want to chime in here as well. With this PR the throttle middleware no longer takes into account the request's route. So if you wanted to throttle more than 1 route you can no longer do this, regardless of whether the user is authenticated or not.

Is this really the desired default behavior? If you set up a throttle middleware on two different routes, their counts overlap?

@lucasmichot
Copy link
Contributor Author

lucasmichot commented Jan 24, 2019

There is no perfect solution for this but it seems to adapt to the most frequent cases.

I personally never use this middleware as it, and always extend it as I need to separate hits in different "buckets" (API and search).

I encourage you to do the same.

@devcircus
Copy link
Contributor

More discussion here: #22929

@trevorgehman
Copy link
Contributor

I'm currently extending it for this reason. Personally I think the best default would be:

  • If applied at the group level, all the routes in the group share the throttle key.
  • If applied to a single route, that route has its own throttle key.

Unfortunately, I don't see an easy way to do this, apart from extending the base middleware and creating two separate throttle middleware for each purpose.

So, I can see the reason to default to what you've done. Most people probably use this to rate limit their entire API. What should probably happen is the docs should be updated to reflect that this middleware is meant to be applied to a single route group.

Copy link

@jhoganrg jhoganrg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure I guess

@laravel laravel locked as resolved and limited conversation to collaborators Jan 28, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants