mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2025-08-08 17:32:13 -04:00
Add a config option for validating 'next_link' parameters against a domain whitelist (#8275)
This is a config option ported over from DINUM's Sydent: https://github.com/matrix-org/sydent/pull/285 They've switched to validating 3PIDs via Synapse rather than Sydent, and would like to retain this functionality. This original purpose for this change is phishing prevention. This solution could also potentially be replaced by a similar one to https://github.com/matrix-org/synapse/pull/8004, but across all `*/submit_token` endpoint. This option may still be useful to enterprise even with that safeguard in place though, if they want to be absolutely sure that their employees don't follow links to other domains.
This commit is contained in:
parent
0f545e6b96
commit
094896a69d
5 changed files with 204 additions and 17 deletions
|
@ -17,6 +17,11 @@
|
|||
import logging
|
||||
import random
|
||||
from http import HTTPStatus
|
||||
from typing import TYPE_CHECKING
|
||||
from urllib.parse import urlparse
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from synapse.app.homeserver import HomeServer
|
||||
|
||||
from synapse.api.constants import LoginType
|
||||
from synapse.api.errors import (
|
||||
|
@ -98,6 +103,9 @@ class EmailPasswordRequestTokenRestServlet(RestServlet):
|
|||
Codes.THREEPID_DENIED,
|
||||
)
|
||||
|
||||
# Raise if the provided next_link value isn't valid
|
||||
assert_valid_next_link(self.hs, next_link)
|
||||
|
||||
# The email will be sent to the stored address.
|
||||
# This avoids a potential account hijack by requesting a password reset to
|
||||
# an email address which is controlled by the attacker but which, after
|
||||
|
@ -446,6 +454,9 @@ class EmailThreepidRequestTokenRestServlet(RestServlet):
|
|||
Codes.THREEPID_DENIED,
|
||||
)
|
||||
|
||||
# Raise if the provided next_link value isn't valid
|
||||
assert_valid_next_link(self.hs, next_link)
|
||||
|
||||
existing_user_id = await self.store.get_user_id_by_threepid("email", email)
|
||||
|
||||
if existing_user_id is not None:
|
||||
|
@ -517,6 +528,9 @@ class MsisdnThreepidRequestTokenRestServlet(RestServlet):
|
|||
Codes.THREEPID_DENIED,
|
||||
)
|
||||
|
||||
# Raise if the provided next_link value isn't valid
|
||||
assert_valid_next_link(self.hs, next_link)
|
||||
|
||||
existing_user_id = await self.store.get_user_id_by_threepid("msisdn", msisdn)
|
||||
|
||||
if existing_user_id is not None:
|
||||
|
@ -603,15 +617,10 @@ class AddThreepidEmailSubmitTokenServlet(RestServlet):
|
|||
|
||||
# Perform a 302 redirect if next_link is set
|
||||
if next_link:
|
||||
if next_link.startswith("file:///"):
|
||||
logger.warning(
|
||||
"Not redirecting to next_link as it is a local file: address"
|
||||
)
|
||||
else:
|
||||
request.setResponseCode(302)
|
||||
request.setHeader("Location", next_link)
|
||||
finish_request(request)
|
||||
return None
|
||||
request.setResponseCode(302)
|
||||
request.setHeader("Location", next_link)
|
||||
finish_request(request)
|
||||
return None
|
||||
|
||||
# Otherwise show the success template
|
||||
html = self.config.email_add_threepid_template_success_html_content
|
||||
|
@ -875,6 +884,45 @@ class ThreepidDeleteRestServlet(RestServlet):
|
|||
return 200, {"id_server_unbind_result": id_server_unbind_result}
|
||||
|
||||
|
||||
def assert_valid_next_link(hs: "HomeServer", next_link: str):
|
||||
"""
|
||||
Raises a SynapseError if a given next_link value is invalid
|
||||
|
||||
next_link is valid if the scheme is http(s) and the next_link.domain_whitelist config
|
||||
option is either empty or contains a domain that matches the one in the given next_link
|
||||
|
||||
Args:
|
||||
hs: The homeserver object
|
||||
next_link: The next_link value given by the client
|
||||
|
||||
Raises:
|
||||
SynapseError: If the next_link is invalid
|
||||
"""
|
||||
valid = True
|
||||
|
||||
# Parse the contents of the URL
|
||||
next_link_parsed = urlparse(next_link)
|
||||
|
||||
# Scheme must not point to the local drive
|
||||
if next_link_parsed.scheme == "file":
|
||||
valid = False
|
||||
|
||||
# If the domain whitelist is set, the domain must be in it
|
||||
if (
|
||||
valid
|
||||
and hs.config.next_link_domain_whitelist is not None
|
||||
and next_link_parsed.hostname not in hs.config.next_link_domain_whitelist
|
||||
):
|
||||
valid = False
|
||||
|
||||
if not valid:
|
||||
raise SynapseError(
|
||||
400,
|
||||
"'next_link' domain not included in whitelist, or not http(s)",
|
||||
errcode=Codes.INVALID_PARAM,
|
||||
)
|
||||
|
||||
|
||||
class WhoamiRestServlet(RestServlet):
|
||||
PATTERNS = client_patterns("/account/whoami$")
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue