javascriptmeteormeteor-blazeddp

DDP Rate limiter on login attempts in meteor


I'm trying to put a DDP rate limiter on the number of login attempts coming in from the client to the server. I've gone through the official documentation but I'm unable to verify if any of it actually works.

I've added the package: ddp-rate-limiter

My server code is:

Meteor.startup(function() {

    var preventBruteForeLogin= {

        type: 'method',
        name: 'Meteor.loginWithPassword'
    }

    DDPRateLimiter.addRule(preventBruteForeLogin, 1, 2000);
    DDPRateLimiter.setErrorMessage("slow down");
});

My understanding with the above is that it has added a rate limiting rule on Meteor.loginWithPassword method that it only allows one attempt every 2 seconds. However, given the little information available in the documentation and elsewhere on the net, I'm unable to figure out if it's actually working or if I've done it wrong. I've also gone through MC's blog on this and frankly I don't understand the coffee script code. Can someone guide me through this?


Solution

  • Firstly according to the Meteor docs

    By default, there are rules added to the DDPRateLimiter that rate limit logins, new user registration and password reset calls to a limit of 5 requests per 10 seconds per session.

    If you want to remove, or replace default limits you should call Accounts.removeDefaultRateLimit() somewhere in your server side code.


    Next you should create method similar to this one below

    NOTE: You should pass only hashed password from client side to server side

    Meteor.methods({
      'meteor.login' ({ username, password }) {
        Meteor.loginWithPassword({ user: username, password })
      }
    })
    

    Then on your server side you should limit just created method.

    if (Meteor.isServer) {
      DDPRateLimiter.setErrorMessage(({ timeToReset }) => {
        const time = Math.ceil(timeToReset / 1000)
        return 'Try again after ' + time + ' seconds.'
      })
    
      DDPRateLimiter.addRule({
        type: 'method',
        name: 'meteor.login',
        connectionId () {
          return true
        },
        numRequests: 1,
        timeInterval: 10000
      })
    }
    

    This one will limit meteor.login method to one call in 10 seconds using DDP connection id. When you call the method on your client side you can get remaining time using callback error object.

    Personally, I do the rate limiting using a slightly changed method from themeteorchef guide. I suggest you to the same, because it is much easier to implement when you build app with more methods to limit and for me, it is more readable. It is written using ES6 syntax. I recommend to read a little bit about it and start using it(you don't have to install additional packages etc.). I am sure that you will quickly like it.

    EDIT

    We found that using wrapping Meteor.loginWithPassword() method in another method may cause security problems with sending password as plain text. Accounts package comes with Accounts._hashPassword(password) method which returns hashed version of our password. We should use it when we call our meteor.login method. It may be done like below

    Meteor.call('meteor.login', username, Accounts._hashPassword(password), function (err) {
      //asyncCallback
    })