不建议与否,我的Django网站会在每个用户的根目录分配一个页面,例如/rgov
。
我使用字符集白名单,因此应该阻止创建index.html
或邪恶的 。我的URL配置也最后路由用户页面,因此不应该通过注册相应的名称来劫持/admin
或其他任何内容。
但是,我想阻止用户注册admin
,因为他们的网页会被破坏。
(Similar question,没有理想的解决方案,如下面的部分所述。)
这是我的尝试:
def is_reserved(username):
r = urls.resolvers.get_resolver('mysite.systemurls')
hit = False
for path in ('/{}', '/{}/'):
try:
r.resolve(path.format(username))
hit = True
break
except urls.exceptions.Resolver404:
continue
return hit
此处,mysite.systemurls
模块定义除用户页面之外的每个URL模式。
这会阻止选择用户名admin
,因为有/admin/
定义的路由。但它不会阻止api
,因为虽然有/api/foo/bar
,但/api/
没有路由。
有没有办法测试是否有一个后缀为/api/
的路由(例如)?由于URL模式是正则表达式,可能不是那么容易,但从理论上讲它应该是可能的。
答案 0 :(得分:0)
这是我不雅的解决方案,对眼睛很抱歉。我使用Django系统检查框架实现了检查。该检查收集应用程序使用的所有URL模式,然后从每个URL模式中提取第一个路径组件。然后确保没有那些第一个路径组件
如果您的网址格式中有一些re_path
会破坏正在做出的假设,那么这将不起作用。
import re
from django import urls
from django.core.checks import register, Error, Tags, Warning
from . import usernames
@register(Tags.urls, Tags.security)
def check_scary_available_usernames(app_configs=None, **kwargs):
'''
Checks that there are no URL patterns /x/y where /x itself is not a pattern.
In this case, /x might be available for user registration, which would be bad.
'''
errors, prefixes = [], set()
r = urls.resolvers.get_resolver('mysite.systemurls')
descend_into_resolver(r, [], errors, prefixes)
# Check to make sure none of these usernames is taken or available
for prefix in prefixes:
if not prefix:
continue
if not usernames.is_reserved(prefix):
errors.append(Warning(
'There is no restriction on registering the forbidden username {}, '
'which would conflict with a URL in use by the system.'.format(prefix)
))
if usernames.user_exists(prefix):
errors.append(Warning(
'A user has the forbidden username {}, which conflicts with a URL in '
'use by the system.'.format(prefix)
))
return errors
def descend_into_resolver(resolver, chain, errors, prefixes):
for up in resolver.url_patterns:
regex = up.pattern.regex.pattern
if isinstance(up, urls.resolvers.URLResolver):
descend_into_resolver(up, chain + [regex], errors, prefixes)
elif isinstance(up, urls.resolvers.URLPattern):
collect_pattern_prefix(chain + [regex], errors, prefixes)
else:
errors.append(Warning(
'Resolver has unexpected URL pattern: {}'.format(repr(up))
))
def collect_pattern_prefix(patterns, errors, prefixes):
# Remember, we are matching against a regular expression pattern! We are not
# taking a robust approach; if it fails, this could report spurious warnings.
uberpattern = r''
for i, pattern in enumerate(patterns):
if i != 0:
pattern = pattern.lstrip('^')
if i != len(patterns) - 1:
pattern = pattern.rstrip('$')
uberpattern += pattern
uberpattern = uberpattern.replace('\\/', '/')
m = re.match(r'^\^?([^/$]*)', uberpattern)
if m is None:
errors.append(Warning(
'Could not determine first component of URL pattern '
'{}'.format(uberpattern)
))
else:
prefixes.add(m.group(1))