Prevent unsafe usernames

If an attacker is able to create an account with a username like "user/calendar.ics", he can access collections of other users.
This commit is contained in:
Unrud 2016-08-01 09:10:23 +02:00
parent f4ebe3f545
commit da1a693620
3 changed files with 20 additions and 1 deletions

View File

@ -311,7 +311,12 @@ class Application:
headers = {"Location": redirect} headers = {"Location": redirect}
return response(status, headers) return response(status, headers)
is_authenticated = self.is_authenticated(user, password) if user and not storage.is_safe_path_component(user):
# Prevent usernames like "user/calendar.ics"
self.logger.info("Refused unsafe username: %s", user)
is_authenticated = False
else:
is_authenticated = self.is_authenticated(user, password)
is_valid_user = is_authenticated or not user is_valid_user = is_authenticated or not user
# Get content # Get content

View File

@ -43,6 +43,8 @@ from configparser import ConfigParser
from importlib import import_module from importlib import import_module
from io import StringIO from io import StringIO
from . import storage
def load(configuration, logger): def load(configuration, logger):
"""Load the rights manager chosen in configuration.""" """Load the rights manager chosen in configuration."""
@ -103,6 +105,9 @@ class Rights(BaseRights):
def authorized(self, user, collection, permission): def authorized(self, user, collection, permission):
user = user or '' user = user or ''
if user and not storage.is_safe_path_component(user):
# Prevent usernames like "user/calendar.ics"
raise ValueError("Unsafe username")
collection_url = collection.path.rstrip("/") or "/" collection_url = collection.path.rstrip("/") or "/"
if collection_url in (".well-known/carddav", ".well-known/caldav"): if collection_url in (".well-known/carddav", ".well-known/caldav"):
return permission == "r" return permission == "r"

View File

@ -103,6 +103,15 @@ def get_etag(text):
return '"%s"' % etag.hexdigest() return '"%s"' % etag.hexdigest()
def is_safe_path_component(path):
"""Check if path is a single component of a path.
Check that the path is safe to join too.
"""
return path and "/" not in path and path not in (".", "..")
def sanitize_path(path): def sanitize_path(path):
"""Make path absolute with leading slash to prevent access to other data. """Make path absolute with leading slash to prevent access to other data.