FAQ
I'm looking for ideas on how to implement a way to detect and block
dictionary attacks. This is not a question of how to implement strong
passwords, but rather the act of limiting logins when too many failed
passwords have been attempted in some period of time.

I also want to do this regardless if the login name is valid or not.
So, an attack on a invalid login name will fail after so many attempts
in a time period just the same as one on a valid login.

The plan is to just report "Exceeded Login attempts -- contact
support or wait X minutes" kind of thing to the user when they exceed
the failed consecutive attempt count.

The plan is to use memcached for a counter per (failed) login. The
cache entry's expires time will be set the first time the cache is
populated.

This gives an attacker a way to flood the cache, of course, and thus a
way to prematurely "expire" cache entries.

Also considered issuing a redirect to a simple server that will delay
the number of failed attempts seconds before redirecting back to the
login page. Any smart attacker would get clued about this an not
follow that redirect. Fun anyways, though. ;)

Anyone doing something like this already? Suggestions? Caveats?


--
Bill Moseley
moseley@hank.org

Search Discussions

  • Steve Atkins at Aug 16, 2007 at 6:32 pm

    On Aug 16, 2007, at 10:13 AM, Bill Moseley wrote:

    I'm looking for ideas on how to implement a way to detect and block
    dictionary attacks. This is not a question of how to implement strong
    passwords, but rather the act of limiting logins when too many failed
    passwords have been attempted in some period of time.

    I also want to do this regardless if the login name is valid or not.
    So, an attack on a invalid login name will fail after so many attempts
    in a time period just the same as one on a valid login.

    The plan is to just report "Exceeded Login attempts -- contact
    support or wait X minutes" kind of thing to the user when they exceed
    the failed consecutive attempt count.

    The plan is to use memcached for a counter per (failed) login. The
    cache entry's expires time will be set the first time the cache is
    populated.

    This gives an attacker a way to flood the cache, of course, and thus a
    way to prematurely "expire" cache entries.

    Also considered issuing a redirect to a simple server that will delay
    the number of failed attempts seconds before redirecting back to the
    login page. Any smart attacker would get clued about this an not
    follow that redirect. Fun anyways, though. ;)

    Anyone doing something like this already? Suggestions? Caveats?
    One approach I've seen for this doesn't block access once
    there's been more than a certain number of failed logins. Instead,
    it has two thresholds. After a very few (2 or 3) failed login attempts
    it requires the user also enter a captcha when trying to login.

    That blocks automated guesses very quickly, but doesn't cause
    legitimate users with poor memories to contact support. (I'm
    assuming they have a higher threshold of failed attempts
    after which they lock the account.)

    Cheers,
    Steve
  • Perrin Harkins at Aug 16, 2007 at 7:06 pm

    On 8/16/07, Bill Moseley wrote:
    I'm looking for ideas on how to implement a way to detect and block
    dictionary attacks. This is not a question of how to implement strong
    passwords, but rather the act of limiting logins when too many failed
    passwords have been attempted in some period of time. [...]
    Anyone doing something like this already? Suggestions? Caveats?
    Yes, there's a plugin that Sam Tregar developed for CGI::Application:
    http://search.cpan.org/~samtregar/CGI-Application-Plugin-RateLimit-1.0/RateLimit.pm

    This was used in Krang (http://krangcms.com/) for exactly what you're
    describing: limiting login attempts.

    You could adapt that design. It uses a database for storage, which
    ought to be fine unless you have massive traffic hitting this login
    page, but I don't see any reason your memcached idea wouldn't work.

    I also did one of these years ago just to limit the number of hits to
    a URL from a specific client within a window of time. It was based on
    Randal's code here:
    http://www.stonehenge.com/merlyn/LinuxMag/col17.html

    I modified it to use a (verified) cookie instead of an IP if possible
    and to count hits rather than CPU. It just returned a Forbidden error
    when people exceeded the limit. At the time, it was a neat design
    because it just used tightly packed data in files, so no locking was
    needed and no database. Today I would use a database instead.

    - Perrin
  • Carl Johnstone at Aug 17, 2007 at 3:56 pm
    Anyone doing something like this already? Suggestions? Caveats?

    You'll almost certainly have to log it per-IP address rather than an a
    cookie or session or anything like that. Any real password-cracking bot is
    unlikely to honour your cookies or session identifiers.

    Which in return means you'll need to be careful, you don't want to block AOL
    users from logging in, just because a few of them all forgot their passwords
    within a few minutes of each other.

    As an idea, how about adding an (increasing) artificial delay into the
    response when the clients send an invalid username/password. It would make
    things increasingly awkward for crackers, whilst still letting good users
    through. A suggestion though it wouldn't work very well in mod_perl or
    similar setups where you can't afford to tie up system resources holding
    onto client connections.

    Carl
  • Bill Moseley at Aug 17, 2007 at 4:32 pm

    On Fri, Aug 17, 2007 at 03:56:23PM +0100, Carl Johnstone wrote:
    Anyone doing something like this already? Suggestions? Caveats?

    You'll almost certainly have to log it per-IP address rather than an a
    cookie or session or anything like that. Any real password-cracking bot is
    unlikely to honour your cookies or session identifiers.
    No, not by IP. Just keyed by login. This is at the application
    layer. The logs will also be watched for other patterns.

    As an idea, how about adding an (increasing) artificial delay into the
    response when the clients send an invalid username/password. It would make
    things increasingly awkward for crackers, whilst still letting good users
    through. A suggestion though it wouldn't work very well in mod_perl or
    similar setups where you can't afford to tie up system resources holding
    onto client connections.
    Ya, that's what I was getting at with:

    Also considered issuing a redirect to a simple server that will delay
    the number of failed attempts seconds before redirecting back to the
    login page. Any smart attacker would get clued about this an not
    follow that redirect. Fun anyways, though. ;)

    --
    Bill Moseley
    moseley@hank.org
  • Wade Stuart at Aug 17, 2007 at 4:52 pm

    Bill Moseley wrote on 08/17/2007 10:32:36 AM:
    On Fri, Aug 17, 2007 at 03:56:23PM +0100, Carl Johnstone wrote:

    Anyone doing something like this already? Suggestions? Caveats?

    You'll almost certainly have to log it per-IP address rather than an a
    cookie or session or anything like that. Any real password-cracking bot
    is
    unlikely to honour your cookies or session identifiers.
    No, not by IP. Just keyed by login. This is at the application
    layer. The logs will also be watched for other patterns.
    Also many web password cracker apps use a huge list of open proxy servers
    and bot farms to farm out the requests -- so tying to the IP may not help
    at all. On the same note tracking IP->login name->falures and looking for
    a pattern of many IP addresses may also give you another insight to
    potential crackers.

    -Wade
  • Carl Johnstone at Aug 17, 2007 at 5:18 pm

    Also considered issuing a redirect to a simple server that will delay
    the number of failed attempts seconds before redirecting back to the
    login page. Any smart attacker would get clued about this an not
    follow that redirect. Fun anyways, though. ;)
    As I just said in the other email, you could use perlbal and not send the
    redirect directly to the client - but to your perlbal proxy, which then
    requests a delay from your stripped http server, which then sends the real
    response.

    Carl
  • Perrin Harkins at Aug 17, 2007 at 4:49 pm

    On 8/17/07, Carl Johnstone wrote:
    You'll almost certainly have to log it per-IP address rather than an a
    cookie or session or anything like that. Any real password-cracking bot is
    unlikely to honour your cookies or session identifiers.
    Last time I needed to do this we had a fallback to IP if no valid
    cookie was found so that it couldn't be evaded by simply refusing all
    cookies. There are workarounds for this workaround though, so it is
    an ongoing battle. AOL proxies were the main reason for doing this.
    As an idea, how about adding an (increasing) artificial delay into the
    response when the clients send an invalid username/password. It would make
    things increasingly awkward for crackers, whilst still letting good users
    through. A suggestion though it wouldn't work very well in mod_perl or
    similar setups where you can't afford to tie up system resources holding
    onto client connections.
    Well, that would be every environment where Catalyst runs. If you
    want to do something fancy, I'd suggest looking at lingerd, a C daemon
    written to take TCP connections handed off from mod_perl. It would
    require some C-level hacking, but I expect you could alter it for this
    purpose.

    - Perrin
  • Carl Johnstone at Aug 17, 2007 at 5:11 pm

    Well, that would be every environment where Catalyst runs. If you
    want to do something fancy, I'd suggest looking at lingerd, a C daemon
    written to take TCP connections handed off from mod_perl. It would
    require some C-level hacking, but I expect you could alter it for this
    purpose.
    Lingerd is only good for apache 1.3 though (or at least I've not come across
    a port of it). So you're talking serious hacking.

    It would probably be easier to use perlbal to do this via a redirect to a
    more lightweight server.

    Carl
  • Bill Moseley at Aug 17, 2007 at 7:09 pm

    On Fri, Aug 17, 2007 at 11:49:42AM -0400, Perrin Harkins wrote:
    On 8/17/07, Carl Johnstone wrote:
    You'll almost certainly have to log it per-IP address rather than an a
    cookie or session or anything like that. Any real password-cracking bot is
    unlikely to honour your cookies or session identifiers.
    Last time I needed to do this we had a fallback to IP if no valid
    cookie was found so that it couldn't be evaded by simply refusing all
    cookies. There are workarounds for this workaround though, so it is
    an ongoing battle. AOL proxies were the main reason for doing this.
    I missed something along the way in this thread. Cookies? Is that to
    block a specific client?

    I'm just thinking of blocking specific logins when too many failed
    logins are attempted. Even in cases where the login is not a valid
    login in the application. Could be implemented somewhat transparently
    by overriding login().

    By the way, any examples with the "new" C::P::Cache to pass expires on a
    cache set? Also look forward to the appearance of
    Catalyst::Plugin::Cache::ControllerNamespacing. Or something to
    partition the cache. I want the sessions and failed login cache to be
    separate. Is August and not seeing nothingmuch around related?

    What's the status of the Cache plugin(s) wrt. backends?

    I want to be able to swap between FastMmap and Memcached via a config
    option.

    --
    Bill Moseley
    moseley@hank.org
  • Perrin Harkins at Aug 17, 2007 at 7:33 pm

    On 8/17/07, Bill Moseley wrote:
    I missed something along the way in this thread. Cookies? Is that to
    block a specific client?
    Yes, as opposed to an IP that could be a proxy.
    I'm just thinking of blocking specific logins when too many failed
    logins are attempted.
    That works if they keep hitting the same login with different
    passwords. Are you concerned about them trying many logins with a
    common password? ("secret") That wouldn't be caught.

    - Perrin
  • Bill Moseley at Aug 17, 2007 at 11:11 pm

    On Fri, Aug 17, 2007 at 02:33:21PM -0400, Perrin Harkins wrote:
    I'm just thinking of blocking specific logins when too many failed
    logins are attempted.
    That works if they keep hitting the same login with different
    passwords. Are you concerned about them trying many logins with a
    common password? ("secret") That wouldn't be caught.
    For this I'm talking about someone trying many passwords on one login.
    Logins may be easier to figure out if you know something about the
    user base (names or email addresses).

    But, I suppose one could use either the login or password (or both
    separately) as the key to the cache entry counting failed logins.



    --
    Bill Moseley
    moseley@hank.org
  • Jonathan Rockway at Aug 18, 2007 at 3:47 am

    Bill Moseley wrote:
    What's the status of the Cache plugin(s) wrt. backends?

    I want to be able to swap between FastMmap and Memcached via a config
    option
    As per the docs:

    # configure a backend or use a store plugin
    __PACKAGE__->config->{cache}{backend} = {
    class => "Cache::FastMmap",
    # ... params ...
    };

    or

    # configure a backend or use a store plugin
    __PACKAGE__->config->{cache}{backend} = {
    class => "Cache::Memcached::Managed",
    # ... params ...
    };


    Feel free to refactor that however you like. But the idea is that
    C::P::Cache doesn't care what backend you use.

    Regards,
    Jonathan Rockway
  • Bill Moseley at Aug 18, 2007 at 7:32 am

    On Fri, Aug 17, 2007 at 09:48:33PM -0500, Jonathan Rockway wrote:
    Bill Moseley wrote:
    What's the status of the Cache plugin(s) wrt. backends?

    I want to be able to swap between FastMmap and Memcached via a config
    option
    As per the docs:

    # configure a backend or use a store plugin
    __PACKAGE__->config->{cache}{backend} = {
    class => "Cache::FastMmap",
    # ... params ...
    };

    or

    # configure a backend or use a store plugin
    __PACKAGE__->config->{cache}{backend} = {
    class => "Cache::Memcached::Managed",
    # ... params ...
    };
    Yes, I like that -- which is why I was asking about the status of the
    plugin. I thought there was a problem from our discussion on IRC:

    (01:13:50 PM) freetime: But FastMmap doesn't work?
    (01:13:50 PM) jrockway: it works for everything except FastMmap, which is broken
    (01:13:53 PM) freetime: ;)
    (01:14:03 PM) jrockway: right, so either use Store::FastMmap or Cache from trunk

    So, any idea when Cache will get pushed to CPAN to fix whatever the
    problem is?

    Feel free to refactor that however you like. But the idea is that
    C::P::Cache doesn't care what backend you use.
    Hum, just spent 45 minutes reading docs and source again. Still not
    the clear.

    --
    Bill Moseley
    moseley@hank.org
  • Jason Kohles at Aug 17, 2007 at 7:10 pm
    On Aug 17, 2007, at 10:56 AM, Carl Johnstone wrote:
    Anyone doing something like this already? Suggestions? Caveats?

    You'll almost certainly have to log it per-IP address rather than
    an a cookie or session or anything like that. Any real password-
    cracking bot is unlikely to honour your cookies or session
    identifiers.
    Real password cracking bots tend to use gigantic lists of open
    proxies, which defeats the IP logging as well.
    Which in return means you'll need to be careful, you don't want to
    block AOL users from logging in, just because a few of them all
    forgot their passwords within a few minutes of each other.
    One way to try and avoid this problem, is to key it by IP and
    username, password cracking bots usually try one username with a
    dictionary of passwords, rather than one password with a dictionary
    of usernames.
    As an idea, how about adding an (increasing) artificial delay into
    the response when the clients send an invalid username/password. It
    would make things increasingly awkward for crackers, whilst still
    letting good users through. A suggestion though it wouldn't work
    very well in mod_perl or similar setups where you can't afford to
    tie up system resources holding onto client connections.
    Instead of delaying the response, one possibility is to send a
    complete response without a login form, just a note that says 'too
    many attempts, try again in X seconds', possibly with a refresh to
    reload the page once the timer expires. This way you don't hold the
    client connections open while waiting for the timer to expire,
    although then it means you have to track on the server side when that
    timer will expire so you can start delivering the form again.
    Adding a delay is useful for console applications, where the user is
    forced to wait for the delay before trying again, but not so useful
    for web applications, where a cracker can just hold a few thousand
    connections open while waiting for the delay to expire.

    I've been contemplating the best way to address this problem on some
    of my own sites, and unfortunately I always end up back at the
    CAPTCHA approach. I don't really like forcing users to solve a
    CAPTCHA every time they log in, but so far it's the only solution
    that I've come up with that doesn't also turn into a massive denial
    of service potential when people start intentionally sending bad
    passwords for people they don't like.

    --
    Jason Kohles
    email@jasonkohles.com
    http://www.jasonkohles.com/
    "A witty saying proves nothing." -- Voltaire
  • Bill Moseley at Aug 17, 2007 at 7:37 pm

    On Fri, Aug 17, 2007 at 02:12:21PM -0400, Jason Kohles wrote:
    Instead of delaying the response, one possibility is to send a
    complete response without a login form, just a note that says 'too
    many attempts, try again in X seconds', possibly with a refresh to
    reload the page once the timer expires. This way you don't hold the
    client connections open while waiting for the timer to expire,
    although then it means you have to track on the server side when that
    timer will expire so you can start delivering the form again.
    The bots don't need a form to sent the request, of course.

    And, as you point out, if I was writing a bot I'd probably only wait
    for the response for a short amount of time -- just to avoid the
    tarpit. You have to imagine that the attacker has unlimited
    resources.

    I have the ability to turn on form tokens on my forms, so to be able
    to post to a form you have to first fetch the single-use token from
    the form. That has been a big help with forms that send mail, but
    also aids in preventing reposting of forms -- in addition to redirect
    after post.

    Unfortunately, often want to have a login form on the home page and
    that page is typically static -- so can't use my token in that
    situation.

    Adding a delay is useful for console applications, where the user is
    forced to wait for the delay before trying again, but not so useful
    for web applications, where a cracker can just hold a few thousand
    connections open while waiting for the delay to expire.

    I've been contemplating the best way to address this problem on some
    of my own sites, and unfortunately I always end up back at the
    CAPTCHA approach. I don't really like forcing users to solve a
    CAPTCHA every time they log in, but so far it's the only solution
    that I've come up with that doesn't also turn into a massive denial
    of service potential when people start intentionally sending bad
    passwords for people they don't like.
    I like the idea of the captcha after a few failed requests. Although,
    if it's a real person having problems logging in then the addition of
    the captcha just make it that much more likely that they will not be
    able to login. Kind of amazing how often I fail the captcha.

    Plus, captcha's are not great for accessibility.

    Maybe better to ask a question in text:

    "What is the airspeed velocity of an unladen swallow?"

    --
    Bill Moseley
    moseley@hank.org
  • Christian Storm at Aug 17, 2007 at 8:25 pm

    I like the idea of the captcha after a few failed requests. Although,
    if it's a real person having problems logging in then the addition of
    the captcha just make it that much more likely that they will not be
    able to login. Kind of amazing how often I fail the captcha.

    Plus, captcha's are not great for accessibility.
    recaptcha has an audio option. Plus your helping a good cause
    of OCRing books from the Internet Archive.
  • Carl Johnstone at Aug 18, 2007 at 6:11 pm

    Bill Moseley wrote:
    Unfortunately, often want to have a login form on the home page and
    that page is typically static -- so can't use my token in that
    situation.
    How about using a variation of the token system. You have a token that's
    valid for any request that you change fairly frequently - say every 5
    minutes. Then you dynamically insert that into the home page.

    Then to give you the effect of a static home page, use apache's mod_cache.

    Finally in your login form, you accept any from the last X tokens where
    X > 2 (you could've cached the page just before the token expires) up to
    whatever life you want to allow.

    Carl
  • Christian Storm at Aug 20, 2007 at 3:47 pm
    What's to stop the bot from grabbing the token from the home page and
    using it in its attack? The token has to be something the
    bot can't readily read, e.g., captcha.
    On Aug 18, 2007, at 10:11 AM, Carl Johnstone wrote:

    Bill Moseley wrote:
    Unfortunately, often want to have a login form on the home page and
    that page is typically static -- so can't use my token in that
    situation.
    How about using a variation of the token system. You have a token
    that's valid for any request that you change fairly frequently -
    say every 5 minutes. Then you dynamically insert that into the home
    page.

    Then to give you the effect of a static home page, use apache's
    mod_cache.

    Finally in your login form, you accept any from the last X tokens
    where X > 2 (you could've cached the page just before the token
    expires) up to whatever life you want to allow.

    Carl


    _______________________________________________
    List: Catalyst@lists.rawmode.org
    Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/
    catalyst@lists.rawmode.org/
    Dev site: http://dev.catalyst.perl.org/
  • Carl Johnstone at Aug 20, 2007 at 6:19 pm

    What's to stop the bot from grabbing the token from the home page and
    using it in its attack? The token has to be something the
    bot can't readily read, e.g., captcha.
    Bill said:

    "I have the ability to turn on form tokens on my forms, so to be able
    to post to a form you have to first fetch the single-use token from
    the form. That has been a big help with forms that send mail, but
    also aids in preventing reposting of forms -- in addition to redirect
    after post."

    So obviously they work for him. Anything that has an effect without causing
    accessibility problems for users has to be a good thing.

    In any case, I was just suggesting a way he could still make his existing
    token system work with a "static" page to save server resources.

    Carl
  • Christian Storm at Aug 20, 2007 at 7:16 pm
    He is referring to reposting of forms that are arrived at via the
    back button, e.g.,
    breaking the cycle submit form -> click back button -> submit form ->
    etc.

    The use case is for single use forms not for security. It wouldn't
    do anything to
    prevent a bot from scraping the HTML for that token and using it to
    submit
    the form.
    On Aug 20, 2007, at 10:19 AM, Carl Johnstone wrote:

    What's to stop the bot from grabbing the token from the home page and
    using it in its attack? The token has to be something the
    bot can't readily read, e.g., captcha.
    Bill said:

    "I have the ability to turn on form tokens on my forms, so to be able
    to post to a form you have to first fetch the single-use token from
    the form. That has been a big help with forms that send mail, but
    also aids in preventing reposting of forms -- in addition to redirect
    after post."

    So obviously they work for him. Anything that has an effect without
    causing accessibility problems for users has to be a good thing.

    In any case, I was just suggesting a way he could still make his
    existing token system work with a "static" page to save server
    resources.

    Carl


    _______________________________________________
    List: Catalyst@lists.rawmode.org
    Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/
    catalyst@lists.rawmode.org/
    Dev site: http://dev.catalyst.perl.org/
  • Antano Solar at Aug 19, 2007 at 5:46 am
    I'm looking for ideas on how to implement a way to detect and block
    dictionary attacks. This is not a question of how to implement strong
    passwords, but rather the act of limiting logins when too many failed
    passwords have been attempted in some period of time.
    I was just wondering why can't the form fields for username and password be
    changed after every x attempts. And the post data checked for the new
    fields.

    1. This way unless the bot waits for the complete form returned after every
    attempt it will send post data with the required fields being null. And if
    it does wait for the complete form returned after every attempt , it is made
    slow considerably.

    2.And after a threshold level , the username and password field can both be
    made of the type password and the label sent as image. this way withth enew
    form the bot doesnt know which is the username field and which is the
    password .

    This only works for 1 username many password atacks or 1 ip attacks.



    Another method i was curious about was to generate the form with x number of
    extra username and password fields whose display style is set as
    none.Thebot might just pick the first pair of username and password
    field.This also gives us knowledge of a bot being used as post values from
    these fields will always be null unless it is being sent by a bot.


    Antano Solar John
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20070819/b0e08ceb/attachment.htm
  • Jonathan Rockway at Aug 19, 2007 at 6:03 am

    Antano Solar wrote:
    I was just wondering why can't the form fields for username and
    password be changed after every x attempts. And the post data checked
    for the new fields.

    This is a good approach, and is automatic if you use the FormCanary or
    RequestToken plugins.

    Regards,
    Jonathan Rockway

    -------------- next part --------------
    A non-text attachment was scrubbed...
    Name: signature.asc
    Type: application/pgp-signature
    Size: 370 bytes
    Desc: OpenPGP digital signature
    Url : http://lists.scsys.co.uk/pipermail/catalyst/attachments/20070819/310265ba/signature.pgp

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupcatalyst @
categoriescatalyst, perl
postedAug 16, '07 at 6:13p
activeAug 20, '07 at 7:16p
posts23
users9
websitecatalystframework.org
irc#catalyst

People

Translate

site design / logo © 2021 Grokbase