honojs / hono

Web framework built on Web Standards
https://hono.dev
MIT License
18.77k stars 535 forks source link

Rate-limiting middleware & Helmet #346

Closed ethndotsh closed 10 months ago

ethndotsh commented 2 years ago

Rate-limiting and helmet middlewares would really be the cherries on top in terms of the built-in middleware. It would also be interesting if the rate-limiting middleware could natively support Redis stores for the storage of IP addresses.

metrue commented 2 years ago

Rate limiting middleware requires a storage (cloudflare KV, Redis, etc), so middleware's options have to expose the store configuration for customization.

ethndotsh commented 2 years ago

For Deno at least, we could use the example provided by oak_rate_limit.

Weilbyte commented 2 years ago

How would we get the client IP? Cloudflare is guaranteed to have the CF-Connecting-IP; but what about deno and bun?

Weilbyte commented 2 years ago

A simple storage to implement would be in-memory storage, this would work for Cloudflare Workers as well (downsides are that the rate limit will be per-worker and that for long rate-limit windows there is a big chance the worker will be evicted, thus starting from scratch). I'm thinking it would be ideal to implement a couple of basic stores (memory, cloudflare kv, redis) and also let the user specify a custom store by passing their own get and put functions in the config object. Maybe even durable object (might be cheaper than KV)?

What do you think @metrue @yusukebe ?

yusukebe commented 2 years ago

Hi @Weilbyte !

I'm thinking it would be ideal to implement a couple of basic stores (memory, cloudflare kv, redis) and also let the user specify a custom store by passing their own get and put functions in the config object.

This is a very good idea!

Since Hono is used on a variety of platforms, it is great that users can choose their favorite storage options. For Cloudflare Workers, I think Durable Objects is better, but I haven't tried it yet.

OultimoCoder commented 1 year ago

Durable objects is definitely better as it is consistent kv is eventually consistent so not idea for rate limiting, especially with short windows.

Weilbyte commented 1 year ago

@OultimoCoder I see, are there any limitations for DO compared to KV?

OultimoCoder commented 1 year ago

Max out at 100 requests a second per object but for a rate limiter you should be instantiating 1 object per ip/user and only really limit endpoints that could be abused like email endpoints.

See my implementation here:

https://github.com/OultimoCoder/cloudflare-planetscale-hono-boilerplate

I am using Hono and made a durable objects rate limiter using the sliding window algorithm, mainly taken from:

https://github.com/honzabit/durable-limiter

You coudl easily turn it into a third party middleware in Hono if you wanted but it would only work with Cloudflare because it used durable objects.

JustJoostNL commented 1 year ago

Would love to see this!

RobertSasak commented 1 year ago

I am currently looking into how to transform node-rate-limiter-flexible for hono as a middleware. node-rate-limiter-flexible

JustJoostNL commented 1 year ago

That would be cool!

RobertSasak commented 1 year ago

Here is an example of a middleware wrapping around rate limiter. Please share your thoughts.

import { RateLimiterMemory } from 'rate-limiter-flexible'

const rateLimiter = new RateLimiterMemory({
    points: 100,
    duration: 100,
})

app.use('*', async (c, next) => {
    const ip = c.req.headers.get('x-forwarded-for')
    if (!ip) {
        return next()
    }
    try {
        await rateLimiter.consume(ip)
    } catch (e) {
        return c.text(
            'Too many requests',
            429,
        )
    }
    await next()
})
JustJoostNL commented 1 year ago

Very nice, how/where are the ip's saved?

RobertSasak commented 1 year ago

Please refer to the rate limiter documentation to explore all available possibilities. The current one employs the instance's memory.

JustJoostNL commented 1 year ago

Nice! Any ETA for the package? 😄

RobertSasak commented 1 year ago

I think there is no need for an extra package and this issue can be closed. Example https://github.com/honojs/hono/issues/346#issuecomment-1699193147 shows how to use any rate limiter.

yusukebe commented 10 months ago

@RobertSasak

Yeah. And now, we have Secure Headers Middleware. Closing now.