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:
parent
f4ebe3f545
commit
da1a693620
@ -311,6 +311,11 @@ class Application:
|
|||||||
headers = {"Location": redirect}
|
headers = {"Location": redirect}
|
||||||
return response(status, headers)
|
return response(status, headers)
|
||||||
|
|
||||||
|
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_authenticated = self.is_authenticated(user, password)
|
||||||
is_valid_user = is_authenticated or not user
|
is_valid_user = is_authenticated or not user
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user