django - 使用 ebextensions 验证 apache 服务器的 HTTP_HOST 标头
问题描述
我有一个托管在 AWS 上的 Django 应用程序。我使用 Elastic Beanstalk 并使用.ebextensions/django.config
文件来输入我的所有自定义服务器端设置。
我已经ALLOWED_HOSTS
设置好,如果有人试图从无效的主机头连接到我的网站,他们会被 Django 阻止。
我收到各种 Django 错误记录电子邮件说Invalid HTTP_HOST header: 123.456.789
。-- 本质上是试图连接和/或上传恶意内容的机器人/扫描程序。
我想在服务器端阻止这些不良请求,因为拥有额外的阻止层似乎更安全,而且我不喜欢收到所有的电子邮件。
在Django 文档中,他们写道“[他们建议] 配置您的 Web 服务器以确保它验证传入的 HTTP 主机标头。” 我想在我的.ebextensions/django.config
文件中这样做。
这是我当前的.ebextensions/django.config
文件:
container_commands:
01_migrate:
command: "python manage.py migrate --noinput"
02_collectstatic:
command: "python manage.py collectstatic --noinput"
option_settings:
aws:elasticbeanstalk:container:python:
WSGIPath: myapp/wsgi.py
aws:elasticbeanstalk:container:python:staticfiles:
/static/: static/
files:
"/etc/httpd/conf.d/ssl_rewrite.conf":
mode: "000644"
owner: root
group: root
content: |
WSGIApplicationGroup %{GLOBAL}
RewriteEngine On
<If "-n '%{HTTP:X-Forwarded-Proto}' && %{HTTP:X-Forwarded-Proto} != 'https'">
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
</If>
Header always set Referrer-Policy no-referrer
Header always set Strict-Transport-Security "max-age=14400; includeSubdomains;"
我相信这都是 apache 配置。我在这个主题上找到了这个 SO 答案,上面写着“拒绝没有设置主机的请求,你可以使用:”
SetEnvIfNoCase Host .+ VALID_HOST
Order Deny,Allow
Deny from All
Allow from env=VALID_HOST
但是,我不确定该代码在做什么(以及它是否是我需要的),以及如何将其转换为 .ebextensions。
最终,我想找出可以添加到 .ebextensions 文件中的内容,以使其在 HTTP_HOST 标头到达 Django 之前对其进行验证。
解决方案
I think you need Django's middleware.
You should create middleware file in your app.
middleware.py (create this file in you django app)
from django.http import JsonResponse
MY_HEADER = 'HTTP_HOST'
class InputCheckMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# <add your logic here>, this is before your code reach django views.
headers = {k: v for k, v in request.META.items() if k.startswith('HTTP_')} # this will return all http headers
if MY_HEADER not in headers:
# make all kinds of validations here
# and return HttpResponse (or subclass. JsonResponse for example) here.
# this case request does not reach in your view.
return JsonResponse({'status_message': 'bad request'})
response = self.get_response(request)
return response
Now, you should add middleware class path in your settings.py file inside MIDDLEWARE
list.
MIDDLEWARE = [
'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',
# your own middleware
'myapp.middleware.InputCheckMiddleware',
]
Middlewares are called per-request. If you use Django1.8, Middleware class structure is different, just check in docs.
推荐阅读
- javascript - Chart.js 工具提示是否不适用于对数或笛卡尔时间轴?
- litedb - 更新 LiteDB 中的整个文档
- ruby - 坚固的 gem 无法构建原生扩展
- javascript - 如果 PUT 同时具有凭据“包含”和 Content-Type,则出现 CORS 错误
- reactjs - 语法错误:运行 npm start 时 React 中出现意外的令牌
- javascript - 如何使用 JavaScript 从脚本标签中选择声明的变量
- ruby-on-rails - Webpacker 未正确插入环境以获取环境的正确配置文件
- sql-server - SQL Server 查询结果按总计排序
- c# - 如何将代理与 Flurl 或 HttpClient 一起使用?
- api - 在一定数量的记录后停止 Mule Batch Job