Move authentication delay into __init__.py and add config

Use the delay for all backends (not only htpasswd).
Add configuration option to configure the delay.
This commit is contained in:
Unrud 2017-05-23 03:11:41 +02:00
parent fb970246e0
commit f2fb07fa84
5 changed files with 18 additions and 5 deletions

3
config
View File

@ -78,6 +78,9 @@
# bcrypt and md5 require the passlib library to be installed. # bcrypt and md5 require the passlib library to be installed.
#htpasswd_encryption = bcrypt #htpasswd_encryption = bcrypt
# Incorrect authentication delay (seconds)
#delay = 1
[rights] [rights]

View File

@ -34,11 +34,13 @@ import itertools
import os import os
import posixpath import posixpath
import pprint import pprint
import random
import socket import socket
import socketserver import socketserver
import ssl import ssl
import sys import sys
import threading import threading
import time
import traceback import traceback
import wsgiref.simple_server import wsgiref.simple_server
import zlib import zlib
@ -383,6 +385,13 @@ class Application:
is_authenticated = False is_authenticated = False
else: else:
is_authenticated = self.Auth.is_authenticated(user, password) is_authenticated = self.Auth.is_authenticated(user, password)
if not is_authenticated:
# Random delay to avoid timing oracles and bruteforce attacks
delay = self.configuration.getfloat("auth", "delay")
if delay > 0:
random_delay = delay * (0.5 + random.random())
self.logger.debug("Sleeping %.3f seconds", random_delay)
time.sleep(random_delay)
# Create principal collection # Create principal collection
if user and is_authenticated: if user and is_authenticated:

View File

@ -58,8 +58,6 @@ import functools
import hashlib import hashlib
import hmac import hmac
import os import os
import random
import time
from importlib import import_module from importlib import import_module
@ -198,6 +196,4 @@ class Auth(BaseAuth):
login, hash_value = line.split(":") login, hash_value = line.split(":")
if login == user and self.verify(hash_value, password): if login == user and self.verify(hash_value, password):
return True return True
# Random timer to avoid timing oracles and simple bruteforce attacks
time.sleep(1 + random.random())
return False return False

View File

@ -93,7 +93,10 @@ INITIAL_CONFIG = OrderedDict([
"help": "htpasswd filename"}), "help": "htpasswd filename"}),
("htpasswd_encryption", { ("htpasswd_encryption", {
"value": "bcrypt", "value": "bcrypt",
"help": "htpasswd encryption method"})])), "help": "htpasswd encryption method"}),
("delay", {
"value": "1",
"help": "incorrect authentication delay"})])),
("rights", OrderedDict([ ("rights", OrderedDict([
("type", { ("type", {
"value": "owner_only", "value": "owner_only",

View File

@ -47,6 +47,8 @@ class TestBaseAuthRequests(BaseTest):
self.configuration.set("storage", "filesystem_fsync", "False") self.configuration.set("storage", "filesystem_fsync", "False")
# Required on Windows, doesn't matter on Unix # Required on Windows, doesn't matter on Unix
self.configuration.set("storage", "close_lock_file", "True") self.configuration.set("storage", "close_lock_file", "True")
# Set incorrect authentication delay to a very low value
self.configuration.set("auth", "delay", "0.002")
def teardown(self): def teardown(self):
shutil.rmtree(self.colpath) shutil.rmtree(self.colpath)