首页 > 解决方案 > 使用 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 之前对其进行验证。

标签: djangoapachehttp-headersamazon-elastic-beanstalkebextensions

解决方案


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.


推荐阅读