Brute force attacks

351 views
Skip to first unread message

Rohit Sethi

unread,
Mar 4, 2011, 4:56:50 PM3/4/11
to Django developers
Hi all, I wanted to revisit a key security discussion. Brute force
attacks are the 7th most prevalent attack by number of incidents in
the Web Hacking Incidents Database (http://projects.webappsec.org/w/
page/13246995/Web-Hacking-Incident-Database), which tracks publicly
disclosed breaches in web application. This is ultimately because many
applications do not have provisions to prevent brute-forcing. Django’s
out of the box admin-site authentication is very awesome – so awesome,
in fact, that inevitably people have and will continue to use it for
more than just administrative users. Clearly Django takes
authentication seriously. Can we revisit the idea of protecting
against brute force authentication out of the box? (http://
groups.google.com/group/django-developers/browse_thread/thread/
7559145e8c85d8c/b96c9a81e97f333b?lnk=gst&q=account
+lockout#b96c9a81e97f333b). In particular, the idea of using
throttling such as http://github.com/simonw/ratelimitcache/ or
http://code.google.com/p/django-brutebuster/. Would you be willing to
discuss further?

My development team is willing to contribute whatever is needed to get
this done if you think it's fruitful

Shawn Milochik

unread,
Mar 4, 2011, 5:22:45 PM3/4/11
to django-d...@googlegroups.com
I have an immediate interest in this discussion. One of my company's
Django apps was recently subjected to an external risk assessment team
audit. They found the fact that three invalid password attempts didn't
lock out the user to be completely unacceptable.

Granted, this is something that I should have applied myself, and if
it were automatically part of Django it would frustrate many
developers because it would inconvenience their users.

However, considering it's an OWASP concern, and likely a wheel which
will be reinvented repeatedly, I would like to see it in Django. I am
willing to put my time into the effort. If Rohit and his team end up
taking on the project I will coordinate with them to see how I can
help.

It seems that any implementation of this would require another value
for settings.py, and I know that's something not done lightly. Also,
the thread referred to above discusses throttling, whereas the
"recommendation" provided to us by the auditors was user lockout
requiring administrator activity (human intervention) to unlock.

So the next question is whether the core dev team is interested in
discussing configurable lockout (number of attempts and human
intervention or timeout to release the lock), throttling, or both.
Then, how to best go about it.

Incidentally, I'll be at PyCon if anyone wants to get together after
hours to work on this during the main days (I won't be at the
sprints).

Shawn

Brendan Smith

unread,
Mar 4, 2011, 6:28:17 PM3/4/11
to django-d...@googlegroups.com
do you guys know about django-axes? (http://code.google.com/p/django-axes/)

it allows you to lock out IP or IP/User Agent combo on a given number of failures.



--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To post to this group, send email to django-d...@googlegroups.com.
To unsubscribe from this group, send email to django-develop...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.




--
Brendan Smith, IT Specialist
National Priorities Project
http://www.nationalpriorities.org
http://www.costofwar.com
http://www.facebook.com/nationalpriorities
413 584 9556

Richard Laager

unread,
Mar 4, 2011, 6:44:10 PM3/4/11
to django-d...@googlegroups.com
On Fri, 2011-03-04 at 17:22 -0500, Shawn Milochik wrote:
> the thread referred to above discusses throttling, whereas the
> "recommendation" provided to us by the auditors was user lockout
> requiring administrator activity (human intervention) to unlock.

This *creates* a denial of service vulnerability, especially if your
usernames are public. (Otherwise the attacker has to guess at them.)

Richard

signature.asc

Emil Filipov

unread,
Mar 4, 2011, 7:32:21 PM3/4/11
to django-d...@googlegroups.com

I'm the author of BruteBuster, and I (obviously) think that an
easy-to-use bruteforce protection is needed in Django. This being said,
I'd suggest to let the code evolve from real-life usage scenarios before
being considered for inclusion in the core or in contrib. So, take your
pick (or write your own lib), see what works and what doesn't, ask
for/implement improvements, then evaluate again. Once there is a clear,
proven winner (something like South ;), then ask for inclusion in Django.

In the particular case of BruteBuster, feel free to contact me directly
with any problems/suggestions (the development of BruteBuster has been
largely neglected, due to the code working OK for our needs and lack of
interest from other parties).


On 03/05/2011 12:22 AM, Shawn Milochik wrote:
> I have an immediate interest in this discussion. One of my company's
> Django apps was recently subjected to an external risk assessment team
> audit. They found the fact that three invalid password attempts didn't
> lock out the user to be completely unacceptable.

> ...
> Also,


> the thread referred to above discusses throttling, whereas the
> "recommendation" provided to us by the auditors was user lockout
> requiring administrator activity (human intervention) to unlock.

I find myself doing similar audits often, and from your description it
looks like the auditors are simply going over a checklist with
prescriptions, without much consideration of what's reasonable. Such
kind of restrictive locking is ridiculous for most use-cases. Unless you
are a very large corporation/government agency/extremely high security
facility, requiring manual intervention from the administrator after 3
failed attempts would simply annoy users and prevent them from doing
their work effectively.

If there is any enforced password strength, bruteforcing would need
*lots* of attempts to succeed. If you hadn't had your coffee in the
morning, on the other hand, it is quite easy to trip over the 3 failed
attempts limit. What happens if the sysadmin is not available to unlock
your account?

On a side note, throttling vs locking - you can implement effective
locking with throttling (say, throttle rate of 3 attempts in 10**6
minutes), but the opposite is not true. I think it is clear which is the
more flexible approach.

--
Best Regards,
Emil Filipov
Cyber Security Consulting Ltd.
http://csc.bg

Russell Keith-Magee

unread,
Mar 5, 2011, 3:43:08 AM3/5/11
to django-d...@googlegroups.com

I'm certainly interested in discussing it. I can't deny that Django's
auth system doesn't protect against brute-force attacks; if there is
something that Django can do 'out of the box', then all the better.

As with any Django feature proposal, nothing will happen unless
someone writes the code and drives the issue. This is essentially what
happened with the thread you referenced -- there wasn't any specific
resistance to the idea, but there wasn't a specific offer to help (at
least, not one that was followed up with action), so the discussion
ended without a resolution. If you're willing to write the code (or
polish the existing code) and drive the discussions, then this could
easily become a feature of the 1.4 release.

I haven't given this a great deal of thought myself, but here are some
initial thoughts:

* Is this something like CSRF, where there should be One True
Solution, Enabled By Default, or is it something where a
backend/plugin interface would be more appropriate? Django has
historically avoided making policy decisions, and this thread has
already shown that there are multiple (and policy lawyers exist that
aren't likely to be flexible on those options).

* Where is the right place for this hook to exist? The two projects
you reference take quite different approaches. Simon's ratelimitcache
is per-view protection -- which means it's easy to accidentally forget
to apply it if you have a custom login, but also more flexible because
you can apply rate limiting to other views, such as an API. Emil's
BruteBuster integrates into the core authentication layer, which is
much more robust, but less immediately flexible for other purposes.

* Is there overlap here with discussions about password hashing?
There was a recent discussion about changing Django's default password
hash function to something that was less susceptible to brute-force
attacks. This was specifically addressing the fact that SHA1 has known
weaknesses, but it only takes a small increase in computational cost
to render a brute-force attack impractical. To what extent would
introducing a higher-cost hashing function remove the need for
specific brute-force protections in auth?

Yours,
Russ Magee %-)

Rohit Sethi

unread,
Mar 5, 2011, 8:40:07 AM3/5/11
to Django developers
Hi Russell, here are my thoughts on your points:

1. I do believe there should be something enabled by default. Some
security conscious developers will go out of there way to integrate a
third party plugin but I believe (and I may be wrong) that many
developers just assume the out-of-the-box authentication is secure
enough to meet their needs. I say this after 6.5 years of application
security consulting and addressing common misconceptions about web app
frameworks repeatedly over the years. This thread has shown that there
has indeed been some policy debate, however I think you'll notice in
the thread Shawn was simply referring to an audit finding - probably
taken from a checklist audit - but as Richard and Emil (and others in
the previous thread) point out this could actually lead to a DoS
vulnerability without appropriate monitoring. I'd strongly advocate
using a throttling mechanism, with the ability to turn it off and
replace with a third party plug-in if somebody desires.

2. I don't have an immediate answer on this. We can investigate and
come up with a proposal before we start developing / integrating

3. I think the the hashing talk was specifically about stolen stored
credentials - in particular, about being able to determine many
passwords from a table of stolen hashes. For brute force protection
against a single account, you'd have a very slow authentication
process to make it infeasible for somebody to try the top 500
passwords on a single user account. For example, if it took 3 seconds
per authentication it would take less than half an hour to perform
this brute forcing (http://www.whatsmypass.com/the-top-500-worst-
passwords-of-all-time) using http://sectools.org/crackers.html.

On Mar 5, 3:43 am, Russell Keith-Magee <russ...@keith-magee.com>
wrote:

Rohit Sethi

unread,
Mar 6, 2011, 3:56:40 PM3/6/11
to Django developers
Ok, we'll go ahead with researching this. Expect to hear back from us
within the next 2-3 weeks (if not this upcoming week)

Thanks,

Rohit
> passwords-of-all-time) usinghttp://sectools.org/crackers.html.

Paul McMillan

unread,
Mar 6, 2011, 7:46:52 PM3/6/11
to django-d...@googlegroups.com
I go back and forth on this issue. Unlike CSRF, there's never going to
be a one size fits all solution for this type of problem. Different
organizations have widely varying requirements, and while I prefer
rate limits, that won't satisfy the auditor whose checklist requires
permanent lockout after X attempts.

That said, Django's current approach of "figure something out
yourself" means that most installs don't get any work in this realm.
We can't defend against every attack scenario, but if we can improve
the most common areas, it will be a substantial gain.

I'm quite interested in working to get better protection into core. I
agree with Rohit that throttling/rate-limiting is going to be where
Django finds a good balance between intrusiveness and security. In
larger systems, this task is often taken care of by the firewall in a
generic one-size-fits-all fashion, but if Django is doing the
limiting, we can provide more specific protection, especially for
users who don't have fine-grained control over their firewall.

If we build a rate limiter into core, it will encourage users to make
use of it in their own projects. It will also allow us to rate limit
other areas of core to improve security - passwords are far from the
only thing susceptible to brute force, and the same framework may be
useful to prevent or discourage DoS.

We need to be careful to provide permissive defaults. Leave the knobs
exposed for organizations which require draconian measures, but for
the average user, convenience trumps security.

At the expense of creating more work, I think that we need to agree on
several facets of the problem before we go writing code:

1) Which attack scenarios do we protect against?

A single machine high-rate attack? A high-rate distributed attack? A
slow distributed attack?

The first of these is the most likely attack - it's easy to implement,
and doesn't require extensive resources or patience. Defenses against
it will also apply (to a lesser extent) in the case of a high-rate
distributed attack. Measures like locking accounts after a number of
login failures prevent the slow attack, but they inconvenience users
and open a very nasty avenue for DoS. I don't know of measures Django
could take which would provide an acceptable balance between
completely preventing this attack and avoiding inconveniencing users.

2) How do we balance protection against DoS concerns?

Since Django installations are usually public-facing, Denial of
Service issues are often a larger concern than brute force attacks
(the entire site being unavailable vs. some number of compromised user
accounts) I strongly oppose the addition of any code which makes
Django significantly more vulnerable to DoS out of the box, even if it
does improve security.

3) What is the appropriate response to an attacker?

Lock the account? Deny access to the whole application? For how long?
Log the attack? At what threshold? We rapidly get into areas that are
in the domain of a full-blown Intrusion Detection System. I think that
Django needs a very minimal set of features in this realm. Log the
attack when over a certain threshold (and log verbosity), block the IP
for a limited period of time, and move on.


In light of these issues, I think that the appropriate solution for
core will be:

* lightweight - we can't compromise performance here. The solution
should be memory-based, and should not write to the database or disk
in most cases. I'm perfectly fine with requiring caching to be enabled
to get protection.

* generic - we should be rate limiting other areas of core, and it
makes sense to provide a way for developers to easily limit their own
applications.

* limited in scope - Django includes many batteries, but it shouldn't
include a full-blown IDS. Throttling and logging for events
significantly outside the norm are enough protection. Anything more
complex becomes application specific.

* pluggable - we can't be all things for all people. We need to design
an interface that is flexible enough to allow people to implement
their own particular set of rules. We do this already in other areas:
databases, caching, sessions, etc. If we can provide a good generic
interface for this, we can include other backends with different
behaviors as they evolve in the community.

So, the tl;dr is that Django needs to include a simple rate limiting
component that is trivial to enable to discourage many brute-force
attacks. I'd like to help make this happen.

-Paul

Rohit Sethi

unread,
Mar 7, 2011, 1:01:13 PM3/7/11
to Django developers
Looks like we're on the same page. I agree that we need something
lightweight designed to repel brute force from a single IP. Something
designed to detect distributed attacks would require more overhead and
monitoring and probably doesn't belong in core. That said, I believe
we should think about logging error messages using OWASP AppSensor
detection point codes (http://www.owasp.org/index.php/
OWASP_AppSensor_Project#tab=Detection_Points) so that a third party
monitoring tool can detect an attack on the application. Perhaps one
day we could extend this standardized security logging to
authorization failures as well.

We balance against DoS by slow incrementing the timeout period. We'll
certainly need to experiment with this to get sensible values, but I'd
suggest thinking about doubling the timeout period for every
successive failed attempt starting from some configurable value such
as 5 seconds up to some configurable maximum such as 4 hours. Ideally
throttling wouldn't kick until at least three failed attempts (also
configurable). To reiterate, all numbers above are just examples -
we'll need to test in some real world conditions to figure out the
best default values.

Eric Hutchinson

unread,
Mar 7, 2011, 3:09:08 PM3/7/11
to Django developers
I would just like to point out that a lot of my users all are behind
various nats, so my webapp typically sees only a few ips that have
valid users on them, and i have users whom i have to remind of their
password on a daily basis. it could lead to a couple of dozen people
being throttled for one person who doesn't know their caps key being
lit up green is why their password isn't working

i'm not saying this is a situation the default should take care of,
but something to keep in mind when designing any backend classes, so
that just the bit that determines the cache key or whatever should be
override-able.

Emil Filipov

unread,
Mar 7, 2011, 5:13:27 PM3/7/11
to django-d...@googlegroups.com
On 7.3.2011 г. 22:09 ч., Eric Hutchinson wrote:
> I would just like to point out that a lot of my users all are behind
> various nats, so my webapp typically sees only a few ips that have
> valid users on them, and i have users whom i have to remind of their
> password on a daily basis. it could lead to a couple of dozen people
> being throttled for one person who doesn't know their caps key being
> lit up green is why their password isn't working
>
> i'm not saying this is a situation the default should take care of,
> but something to keep in mind when designing any backend classes, so
> that just the bit that determines the cache key or whatever should be
> override-able.

I believe that a block against the combo IP+Usrname takes care of this
problem. It is enough to block most of the non-distributed attacks
(unless the attacker is bruteforcing thousands of usernames), and it
would provide significant resistance against distributed attacks as well.

Luke Plant

unread,
Mar 7, 2011, 6:48:30 PM3/7/11
to django-d...@googlegroups.com
On 04/03/11 21:56, Rohit Sethi wrote:

> Hi all, I wanted to revisit a key security discussion. Brute force
> attacks are the 7th most prevalent attack by number of incidents in
> the Web Hacking Incidents Database (http://projects.webappsec.org/w/
> page/13246995/Web-Hacking-Incident-Database), which tracks publicly
> disclosed breaches in web application. This is ultimately because many
> applications do not have provisions to prevent brute-forcing. Django’s
> out of the box admin-site authentication is very awesome – so awesome,
> in fact, that inevitably people have and will continue to use it for
> more than just administrative users. Clearly Django takes
> authentication seriously. Can we revisit the idea of protecting
> against brute force authentication out of the box? (http://
> groups.google.com/group/django-developers/browse_thread/thread/
> 7559145e8c85d8c/b96c9a81e97f333b?lnk=gst&q=account
> +lockout#b96c9a81e97f333b).

For me, since you can implement this as an external app for most cases,
the question is: why should we include something in core or contrib?

The answer must be either:

1) we need this out-of-the-box in the normal case.
2) having multiple solutions hinders web development, rather than
fostering beneficial competition that can evolve faster than
Django's release cycle.

Regarding 1), if we aim for something out-of-the-box, we *have* to make
all kinds of decisions, as already discussed, like:

- on what basis to we detect brute force attacks?

- what rates do we limit to?

- what action do we actually take when we detect attacks?

- where do we store failed attempts? (database, cache?)

Most of the answers would be inappropriate in large number of cases, and
we would then need a whole bunch of settings to allow customisation to
these. At the very least, we would need to be able to disable the whole
thing, and use something else.

Regarding 2), I don't see that having multiple solutions, even multiple
solutions in a single project, is a problem, unlike something like the
'messages' framework that was added to contrib, where there is obvious
benefit from a single solution that provides most of the features that
most apps need.

Further, I envisage that adding a solution to core/contrib might tend to
make it *harder* to add a custom solution, since bundled apps (e.g. the
admin) will use the bundled solution. If that solution uses view
decorators like Simon's ratelimitcache, we've hardcoded something that
might be inappropriate.

I don't see the point of trying to add this to Django unless we can
answer these questions, but from the sounds of the thread so far, I
suspect we cannot provide sensible defaults with enough customization
hooks to make it worthwhile.

In the end, I'm afraid this will end up as one more example of Django
"badteries"
<http://www.scribd.com/doc/37113340/Why-Django-Sucks-and-How-we-Can-Fix-it>
(That presentation of Eric's is really good, BTW, video here
<http://djangocon.blip.tv/file/4112452/>)

Regards,

Luke

--
"Despair: It's always darkest just before it goes pitch black."
(despair.com)

Luke Plant || http://lukeplant.me.uk/

Rohit Sethi

unread,
Mar 7, 2011, 9:11:19 PM3/7/11
to Django developers
Luke, I guess the real question is what's the risk of not including it
out-of-the-box? What happens if Django users *do not* go out of their
way to use a third party tool to protect against brute-forcing? Seems
to me that they're likely susceptible in the absence of a network
device or service designed to protect against application-layer brute
forcing. How many Django auth users implement one of these third party
account throttling/lockout plugins today? How many of the developers
who do not implement these tools are relying on django.contrib.auth to
protect confidential or integral data within their applications? If
the vast majority of Django apps using auth have brute-force
protection in place already OR they're okay with being susceptible to
a script-kiddie attack then there really *isn't* a need for this and
we should drop it. My suspicion is that it's probably the opposite but
I readily admit I might be wrong.

The concerns you bring up are valid - there aren't obvious answers
that will work in the vast majority of cases. I'd like to think we can
err on the side of being permissive: the vast majority of valid end
users should not experience any impact to their authentication. This
may not pass an ISO27001 audit but it's going to substantially help
protect your application.

One of the biggest challenge seems to be configuration, and a real
desire not to add more configuration options. I have to plead
ignorance here and say that I don't know if you've found other ways
around this in the past. You're right that this won't work without
configuration options and the ability to turn-off / use a different
plugin.

Perhaps another option to explore is to bundle this, along with other
important security measures such as password complexity configuration,
into a security package for Django rather than adding it to contrib. I
would prefer not to go down this route for something as important as
authentication throttling as I think many Django users believe that
Django's inherent security is good enough for their needs. Again,
please correct me if my assumptions here are wrong.
> <http://www.scribd.com/doc/37113340/Why-Django-Sucks-and-How-we-Can-Fi...>

Michael Radziej

unread,
Mar 8, 2011, 4:10:08 AM3/8/11
to Rohit Sethi, Django developers
On Mon, 7 Mar 2011 18:11:19 -0800 (PST), Rohit Sethi <rkl...@gmail.com> wrote:
> Luke, I guess the real question is what's the risk of not including it
> out-of-the-box?

Well, it *is* not included out-of-the-box. The universe has not collapsed.

While I appreciate your proposal, I don't see the immediate necessity to
stop all other django development. As Russell wrote: Nothing will happen
until somebody gets their hands dirty and writes some code. And the
past has proved that this happens much better independently from the
release cycle of the django core. When a good solution has been found,
it might go into the core.

It's simply easier to try out various concepts out of the core.


Kind regards

Michael

Rohit Sethi

unread,
Mar 8, 2011, 7:55:11 AM3/8/11
to Django developers
You're right - let's not argue this anymore. We'll work on something
and if it makes it into contrib, great, if not - well I guess we're no
worse off than we are right now.

In the interim I propose that we add a note to
http://docs.djangoproject.com/en/dev/topics/auth/ to let users know
that brute-force prevention doesn't come out of the box. Does that
sound fair?

On Mar 8, 4:10 am, Michael Radziej <m...@spieleck.de> wrote:

shmengie

unread,
Mar 8, 2011, 12:05:37 PM3/8/11
to Django developers

Hi Guys,

This topic has me crawling out of the woodwork, I would like to
contribute to the effort.

Can't see this making it into django's core, although I would like to
see it there, I think complexities would inhibit beginners and
veterans alike, although, it would be nice if it could be configured
and enabled.

At a minimum, it's going to require a table or two in the auth realm,
and additional hooks on the rack.

What I would like to see is something akin to a bank's level of
security that could be throttled to preference.


-Joe
Reply all
Reply to author
Forward
0 new messages