Baroshem / nuxt-security

🛡 Automatically configure your app to follow OWASP security patterns and principles by using HTTP Headers and Middleware
https://nuxt-security.vercel.app/
MIT License
819 stars 56 forks source link

Configure RateLimiter with redis from nitro hooks #508

Closed gpataciertocom closed 3 months ago

gpataciertocom commented 3 months ago

Hi! First of all, thanks for this awesome package, I really like it.

However, I'm facing an issue I can't resolve and don't know where could I find more information.

Problem is related with rate-limiter configuration, specifically when configuring a redis driver. If I define a redis configuration at nuxt.config.js, then, It won't be overwritten by nitro hook when using runtime-config hooks with defineNitroPlugin.

Looks like its not overwritting redis section. I don't know if I'm missing something. Although the hook is fired, it's not taking effect with redis configuration.

Version

nuxt-security: 2.0.0-rc.9 nuxt: 3.11.2

Steps to reproduce

  1. Install nuxt-security npx nuxi@latest module add security
  2. add configuration at nuxt.config.ts
    security: {
    rateLimiter: {
      driver: {
        name: "redis",
        options: {
          host: "192.168.0.23",
          post: 6379,
        }
      }
    }
    },
  3. Create a server plugin with defineNitroPlugin to overwrite config from nuxt.config.js.
    export default defineNitroPlugin((nitroApp) => {
    nitroApp.hooks.hook('nuxt-security:routeRules', (appSecurityOptions) => {
    appSecurityOptions['/**'] = defuReplaceArray(
      {
        rateLimiter: {
          tokensPerInterval: 3, // <-- it works!
          driver: { // <--- being ignored?
            name: 'redis',
            options: {
              host: '192.168.0.50',
              port: 6379,
              username: 'some-user',
              password: 'some-password'
            }
          }
        }
      },
      appSecurityOptions['/**']
    );
    });
    });
  4. Register the plugin using defineNuxtModule
    export default defineNuxtModule({
    meta: {
    name: 'security',
    configKey: 'security'
    },
    setup () {
    const { resolve } = createResolver(import.meta.url);
    addServerPlugin(resolve('./plugins/security.ts'));
    }
    });
  5. run npm run dev

App tries to connect to 192.168.0.23:6379 from nuxt.config.js instead of 192.168.0.50 provided in hook from my plugin.

What is Expected?

Plugin configuration should overwrite configuration from nuxt.config.js.

What is actually happening?

Cannot overwrite redis driver config for rate-limiter. It keeps using nuxt.config.js data instead of plugin config.

I need help with this please. I need to define redis configuration using nitro hooks because I'm using .env variables for host, port, username and password. Thanks!

vejja commented 3 months ago

Hi @gpataciertocom

It is true that the ‘driver’ key of the ‘rateLimiter’ cannot be modified by the runtime hook.

@Baroshem do you think we could support changing this?

also quick note: I don’t think your step 4 is required. In addition you are re-defining the ‘security’ name I believe

Baroshem commented 3 months ago

Hey there!

That is true, it is not supported yet. I think we could support this (I don't know yet how to do that but we could think about it) but I am not sure when this could be implemented. For now we are working on closing the features for upcoming 2.0.0 release and this one is a nice to have that we could plan for after my back from holidays (mid september).

Unless you Sebastien or @gpataciertocom would have time to work on it in the meantime and publish a new minor version with it :)

vejja commented 3 months ago

After further review of the source code, I'm not sure we need to change the codebase to allow this functionality. It should be possible to use the standard runtimeConfig key I believe.

@gpataciertocom can you try in nuxt.config.js:

export default defineNuxtConfig({
  runtimeConfig: {
    security: {
      rateLimiter: {
        driver: {
          name: "redis",
          options: {
            host: "192.168.0.23",
            post: 6379,
          }
        }
      }
    },
  }
})

The standard runtimeConfig key in Nuxt is provided exactly for this use-case where you want to load your secrets from .env or other places. See https://nuxt.com/docs/guide/going-further/runtime-config

You won't need to write a runtime hook and won't have to define a Nitro plugin, which means you can then scratch steps 3 and 4 altogether

gpataciertocom commented 3 months ago

Hi! Thanks for reply! Yes, thats true, I can use my .env variables there, so I don't need the hook:

export default defineNuxtConfig({
  runtimeConfig: {
    security: {
      rateLimiter: {
        driver: {
          name: process.env.NODE_ENV === 'development' ? 'lruCache' : 'redis',
          options: {
            host: process.env.REDIS_HOST,
            post: process.env.REDIS_PORT,
          }
        }
      }
    },
  }
})

And its the same of setting it directly in security key.

export default defineNuxtConfig({
  security: {
    rateLimiter: {
      driver: {
        name: process.env.NODE_ENV === 'development' ? 'lruCache' : 'redis',
        options: {
          host: process.env.REDIS_HOST,
          post: process.env.REDIS_PORT,
        }
      }
    }
  },
})

It's much more simpler that what I was trying... A lot of thanks!

vejja commented 3 months ago

Wonderful ! This will allow you to also pass username and password. Please have a look at the official Nuxt documentation to make sure the variables are injected in production - especially the naming convention (NUXT_…) and the mandatory runtimeConfig field definitions. Cheers

Baroshem commented 3 months ago

Awesome, thank you @vejja for this! 💚