有没有一种方法在Django中设置允许的主机IP范围?
就像这样:
ALLOWED_HOSTS = ['172.17.*.*']
有没有一种方法在Django中设置允许的主机IP范围?
就像这样:
ALLOWED_HOSTS = ['172.17.*.*']
不,目前这是不可能的。根据文档,仅支持以下语法:
['www.example.com'] # Fully qualified domain
['.example.com'] # Subdomain wildcard, matches example.com and www.example.com
['*'] # Matches anything
如果您查看validate_host
方法的实现,您会发现仅使用'*'
是被允许的,但是将*
作为字符串的通配符(例如'172.17.*.*'
)是不支持的。我在 Django 上发布了一个工单,然后被告知可以通过以下方式实现:
from socket import gethostname, gethostbyname
ALLOWED_HOSTS = [ gethostname(), gethostbyname(gethostname()), ]
更新。如果您正在使用Docker,则以下代码更好,因为gethostbyname无法获取正确的信息。
from socket import gethostname, gethostbyname, gethostbyname_ex
ALLOWED_HOSTS = [ gethostname(), ] + list(set(gethostbyname_ex(gethostname())[2]))
将它转换为集合的原因是gethostbyname_ex可能会返回重复项。
Django网站上的链接是:
ALLOWED_HOSTS = [ gethostname(), gethostbyname(gethostname()), '.example.com']
- KurtMozilla发布了一个名为django-allow-cidr的Python包,旨在解决这个问题。
公告博客文章解释了它对于像健康检查这样没有Host
标题只使用IP地址的事情非常有用。
您需要略微更改您的IP地址'172.17.*.*'
,使其成为像172.17.0.0/16
这样的CIDR范围。
172.17.malicious.host.com
这样恶意的东西。 - Cole10.0.0.0/16
添加到 ALLOWED_CIDR_NETS
中完美解决了问题。ALLOWED_CIDR_NETS = ['10.0.0.0/16']
- Goranself.allowed_cidr_nets = [IPNetwork(net) for net in allowed_cidr_nets]
for net in self.allowed_cidr_nets:
你可以在 https://netaddr.readthedocs.io/en/latest/tutorial_01.html#slicing 中了解更多关于 IPNetwork 的信息,其中“使用生成器确保与大型 IP 子网的处理效率高。” - sanchaz这是一个快速而简单的解决方案。
ALLOWED_HOSTS += ['172.17.{}.{}'.format(i,j) for i in range(256) for j in range(256)]
如果我们研究Django如何验证主机,我们就能更好地了解如何制作更灵活的ALLOWED_HOSTS
条目:
def validate_host(host, allowed_hosts):
"""
Validate the given host for this site.
Check that the host looks valid and matches a host or host pattern in the
given list of ``allowed_hosts``. Any pattern beginning with a period
matches a domain and all its subdomains (e.g. ``.example.com`` matches
``example.com`` and any subdomain), ``*`` matches anything, and anything
else must match exactly.
Note: This function assumes that the given host is lowercased and has
already had the port, if any, stripped off.
Return ``True`` for a valid host, ``False`` otherwise.
"""
return any(pattern == '*' or is_same_domain(host, pattern) for pattern in allowed_hosts)
. . .
def is_same_domain(host, pattern):
"""
Return ``True`` if the host is either an exact match or a match
to the wildcard pattern.
Any pattern beginning with a period matches a domain and all of its
subdomains. (e.g. ``.example.com`` matches ``example.com`` and
``foo.example.com``). Anything else is an exact string match.
"""
if not pattern:
return False
pattern = pattern.lower()
return (
pattern[0] == '.' and (host.endswith(pattern) or host == pattern[1:]) or
pattern == host
)
这里有一个 RegexHost
工具,可以通过此验证。
class RegexHost(str):
def lower(self):
return self
def __init__(self, pattern):
super().__init__()
self.regex = re.compile(pattern)
def __eq__(self, other):
# override the equality operation to use regex matching
# instead of str.__eq__(self, other)
return self.regex.match(other)
以下是使用示例:
# this matches '172.17.*.*' and also many impossible IPs
host = RegexHost(r'172\.17\.[0-9]{1,3}\.[0-9]{1,3}')
# Un-comment the below assertions to prove to yourself that this host
# validation works. Do not leave these assertions active in
# production code for startup performance considerations.
# assert all(host == f'172.17.{i}.{j}' for i in range(256) for j in range(256))
# assert not any(host == f'172.18.{i}.{j}' for i in range(256) for j in range(256))
ALLOWED_HOSTS = [host]
from django.http import HttpResponseForbidden
class FilterHostMiddleware(object):
def process_request(self, request):
allowed_hosts = ['127.0.0.1', 'localhost'] # specify complete host names here
host = request.META.get('HTTP_HOST')
if host[len(host)-10:] == 'dyndns.org': # if the host ends with dyndns.org then add to the allowed hosts
allowed_hosts.append(host)
elif host[:7] == '192.168': # if the host starts with 192.168 then add to the allowed hosts
allowed_hosts.append(host)
if host not in allowed_hosts:
raise HttpResponseForbidden
return None
这个解决方案对我很有效:
django-allow-cidr==0.5.0
添加到你的 requirements.txt 文件中MIDDLEWARE = [ 'allow_cidr.middleware.AllowCIDRMiddleware', ... ]
ALLOWED_CIDR_NETS = ['172.17.0.0/16']
像这样:
ALLOWED_HOSTS = ['127.0.0.1', 'localhost', '.domain.com']
ALLOWED_CIDR_NETS = ['172.17.0.0/16']
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'allow_cidr.middleware.AllowCIDRMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ALLOWED_HOSTS = ['*']
(出于安全原因不建议这样做),但我还没有看到像您的示例那样的东西。我仍然倾向于“是的”,但在看到明确说明的参考资料之前,我仍然不会被说服。这可能是一个愚蠢的问题,但您是否尝试过它,以查看它是否会在django中引发任何错误? - Ian