本番Djangoプロジェクトのセキュリティを強化する方法
序章
Django アプリケーションの開発は、そのアプローチが柔軟でスケーラブルであるため、迅速でクリーンなエクスペリエンスになります。 Djangoは、プロジェクトを本番環境にシームレスに準備するのに役立つさまざまなセキュリティ指向の設定も提供します。 ただし、本番環境への展開に関しては、プロジェクトをさらに保護する方法がいくつかあります。 設定を分割してプロジェクトを再構築すると、環境に基づいてさまざまな構成を簡単に設定できます。 レバレッジ dotenv
環境変数または機密設定を非表示にすると、プロジェクトを危険にさらす可能性のある詳細を公開しないようになります。
これらのさまざまな戦略や機能の実装には最初は時間がかかるように思われるかもしれませんが、実用的なワークフローを開発することで、セキュリティや生産性を損なうことなくプロジェクトのリリースを展開できます。
このチュートリアルでは、環境ベースの設定を実装および構成することにより、Django開発にセキュリティ指向のワークフローを活用します。 dotenv
、およびDjangoの組み込みのセキュリティ設定。 これらの機能はすべて互いに補完し合っており、Djangoプロジェクトのバージョンは、デプロイに使用できるさまざまなアプローチに対応できるようになります。
前提条件
このガイドを開始する前に、次のものが必要です。
- 既存のDjangoプロジェクト。 まだセットアップしていない場合は、Djangoのインストール方法と開発環境のセットアップチュートリアルを使用してセットアップできます。 このチュートリアルでは、
testsite
例として、このチュートリアルのプロジェクト。 - このDjango開発チュートリアルシリーズは、Djangoのファイル構造とそのコア設定を理解するための優れた方法です。
注:既存のDjangoプロジェクトを使用している場合は、要件が異なる場合があります。 このチュートリアルでは、特定のプロジェクト構造を提案していますが、必要に応じて、このチュートリアルの各セクションを個別に使用することもできます。
ステップ1—Djangoの設定を再構築する
この最初のステップでは、最初に settings.py
環境固有の構成にファイルします。 これは、開発と本番など、異なる環境間でプロジェクトを移動する必要がある場合に適しています。 この配置は、さまざまな環境での再構成が少なくなることを意味します。 代わりに、環境変数を使用して構成を切り替えます。これについては、チュートリアルの後半で説明します。
と呼ばれる新しいディレクトリを作成します settings
プロジェクトのサブディレクトリ:
- mkdir testsite/testsite/settings
(私たちが使用している前提条件に従って testsite
、ただし、ここでプロジェクトの名前に置き換えることができます。)
このディレクトリは現在のディレクトリに置き換わります settings.py
構成ファイル; 環境ベースの設定はすべて、このフォルダーに含まれる個別のファイルに含まれます。
あなたの新しいで settings
フォルダ、3つのPythonファイルを作成します。
- cd testsite/testsite/settings
- touch base.py development.py production.py
The development.py
ファイルには、開発中に通常使用する設定が含まれます。 と production.py
本番サーバーで使用するための設定が含まれます。 本番構成では開発環境では機能しない設定が使用されるため、これらは別々に保持する必要があります。 たとえば、HTTPSの使用の強制、ヘッダーの追加、本番データベースの使用などです。
The base.py
設定ファイルには、 development.py
と production.py
から継承します。 これは、冗長性を減らし、コードをよりクリーンに保つためです。 これらのPythonファイルは置き換えられます settings.py
、だからあなたは今削除します settings.py
Djangoの混乱を避けるため。
まだあなたの中に settings
ディレクトリ、名前を変更 settings.py
に base.py
次のコマンドを使用します。
- mv ../settings.py base.py
これで、新しい環境ベースの設定ディレクトリの概要が完成しました。 プロジェクトはまだ新しい構成を理解していないので、次にこれを修正します。
ステップ2—使用 python-dotenv
現在、Djangoは新しい設定ディレクトリまたはその内部ファイルを認識しません。 したがって、環境ベースの設定で作業を続ける前に、Djangoをで動作させる必要があります python-dotenv
. これは、環境変数をからロードする依存関係です。 .env
ファイル。 これは、Djangoが内部を調べることを意味します .env
プロジェクトのルートディレクトリにあるファイルを使用して、使用する設定構成を決定します。
プロジェクトのルートディレクトリに移動します。
- cd ../../
python-dotenvをインストールします。
- pip install python-dotenv
次に、使用するようにDjangoを構成する必要があります dotenv
. これを行うには、2つのファイルを編集します。 manage.py
、開発用、および wsgi.py
、生産用。
編集から始めましょう manage.py
:
- nano manage.py
次のコードを追加します。
import os
import sys
import dotenv
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'testsite.settings.development')
if os.getenv('DJANGO_SETTINGS_MODULE'):
os.environ['DJANGO_SETTINGS_MODULE'] = os.getenv('DJANGO_SETTINGS_MODULE')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()
dotenv.load_dotenv(
os.path.join(os.path.dirname(__file__), '.env')
)
保存して閉じます manage.py
そして開く wsgi.py
編集用:
- nano testsite/wsgi.py
次の強調表示された行を追加します。
import os
import dotenv
from django.core.wsgi import get_wsgi_application
dotenv.load_dotenv(
os.path.join(os.path.dirname(os.path.dirname(__file__)), '.env')
)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'testsite.settings.development')
if os.getenv('DJANGO_SETTINGS_MODULE'):
os.environ['DJANGO_SETTINGS_MODULE'] = os.getenv('DJANGO_SETTINGS_MODULE')
application = get_wsgi_application()
これらのファイルの両方に追加したコードは、2つのことを行います。 まず、Djangoが実行されるたびに—manage.py
開発を実行するために、 wsgi.py
生産のために-あなたはそれをあなたの .env
ファイル。 ファイルが存在する場合は、Djangoに次の設定ファイルを使用するように指示します。 .env
それ以外の場合は、デフォルトで開発構成を使用することをお勧めします。
ファイルを保存して閉じます。
最後に、を作成しましょう .env
プロジェクトのルートディレクトリ:
- nano .env
次に、次の行を追加して、環境を開発に設定します。
DJANGO_SETTINGS_MODULE="testsite.settings.development"
注:追加 .env
あなたに .gitignore
ファイルなので、コミットに含まれることはありません。 このファイルを使用して、公開したくないパスワードやAPIキーなどのデータを含めます。 プロジェクトが実行されているすべての環境には、独自の環境があります .env
その特定の環境の設定で。
を作成することをお勧めします .env.example
プロジェクトに含めて、新しいものを簡単に作成できるようにします .env
必要な場所ならどこでも。
したがって、デフォルトではDjangoは testsite.settings.development
、しかしあなたが変更した場合 DJANGO_SETTINGS_MODULE
に testsite.settings.production
たとえば、本番構成の使用を開始します。 次に、 development.py
と production.py
設定構成。
ステップ3—開発および本番環境の設定を作成する
次に、あなたはあなたを開きます base.py
環境ごとに変更する構成を個別に追加します development.py
と production.py
ファイル。 The production.py
本番データベースのクレデンシャルを使用する必要があるため、それらが利用可能であることを確認してください。
注:環境に基づいて、構成する必要のある設定を決定するのはあなた次第です。 このチュートリアルでは、本番環境と開発環境の一般的な例(つまり、セキュリティ設定と個別のデータベース構成)についてのみ説明します。
このチュートリアルでは、前提条件のチュートリアルのDjangoプロジェクトをサンプルプロジェクトとして使用しています。 から設定を移動します base.py
に development.py
. 開くことから始めます development.py
:
- nano testsite/settings/development.py
まず、からインポートします base.py
-このファイルはから設定を継承します base.py
. 次に、開発環境用に変更する設定を転送します。
from .base import *
DEBUG = True
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
この場合、開発に固有の設定は次のとおりです。 DEBUG
、 あなたはこれを必要とします True
開発中ですが、本番環境ではありません。 と DATABASES
、本番データベースではなくローカルデータベース。 ここでは開発用にSQLiteデータベースを使用しています。
注:セキュリティ上の理由から、DjangoのDEBUG出力には、文字列を含む可能性のある設定は表示されません。 API
, KEY
, PASS
, SECRET
, SIGNATURE
、 また TOKEN
.
これは、プロジェクトを誤って本番環境にデプロイした場合に、秘密が明かされないようにするためです。 DEBUG
まだ有効です。
そうは言っても、プロジェクトを公に展開しないでください DEBUG
有効。 プロジェクトのセキュリティを危険にさらすだけです。
次に、に追加しましょう production.py
:
- nano testsite/settings/production.py
生産はに似ています development.py
、ただし、データベース構成が異なり、 DEBUG
に設定 False
:
from .base import *
DEBUG = False
ALLOWED_HOSTS = []
DATABASES = {
'default': {
'ENGINE': os.environ.get('SQL_ENGINE', 'django.db.backends.sqlite3'),
'NAME': os.environ.get('SQL_DATABASE', os.path.join(BASE_DIR, 'db.sqlite3')),
'USER': os.environ.get('SQL_USER', 'user'),
'PASSWORD': os.environ.get('SQL_PASSWORD', 'password'),
'HOST': os.environ.get('SQL_HOST', 'localhost'),
'PORT': os.environ.get('SQL_PORT', ''),
}
}
与えられたデータベース構成の例では、次を使用できます dotenv
デフォルトを含めて、指定された各資格情報を構成します。 プロジェクトの製品版用にデータベースをすでにセットアップしていると仮定すると、提供されている例の代わりに構成を使用してください。
これで、に基づいてさまざまな設定を使用するようにプロジェクトを構成しました。 DJANGO_SETTINGS_MODULE
の .env
. 使用した設定例を考えると、本番環境設定を使用するようにプロジェクトを設定すると、 DEBUG
になります False
, ALLOWED_HOSTS
が定義され、サーバーで(すでに)構成した別のデータベースの使用を開始します。
ステップ4—Djangoのセキュリティ設定を操作する
Djangoには、プロジェクトに追加できるセキュリティ設定が含まれています。 このステップでは、本番プロジェクトに不可欠と見なされるセキュリティ設定をプロジェクトに追加します。 これらの設定は、プロジェクトが一般に公開されている場合に使用することを目的としています。 開発環境でこれらの設定を使用することはお勧めしません。 したがって、このステップでは、これらの設定を production.py
構成。
ほとんどの場合、これらの設定により、セッションCookie 、CSRF Cookie、HTTPからHTTPSへのアップグレードなどのさまざまなWeb機能にHTTPSの使用が強制されます。 したがって、サーバーを指すドメインをまだサーバーに設定していない場合は、このセクションをしばらくお待ちください。 サーバーを展開できるようにセットアップする必要がある場合は、結論でこれに関する推奨記事を確認してください。
最初に開く production.py
:
- nano production.py
コードに続く説明に従って、ファイルに、プロジェクトで機能する強調表示された設定を追加します。
from .base import *
DEBUG = False
ALLOWED_HOSTS = ['your_domain', 'www.your_domain']
DATABASES = {
'default': {
'ENGINE': os.environ.get('SQL_ENGINE', 'django.db.backends.sqlite3'),
'NAME': os.environ.get('SQL_DATABASE', os.path.join(BASE_DIR, 'db.sqlite3')),
'USER': os.environ.get('SQL_USER', 'user'),
'PASSWORD': os.environ.get('SQL_PASSWORD', 'password'),
'HOST': os.environ.get('SQL_HOST', 'localhost'),
'PORT': os.environ.get('SQL_PORT', ''),
}
}
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_SSL_REDIRECT
すべてのHTTPリクエストをHTTPSにリダイレクトします(免除されていない場合)。 これは、プロジェクトが常に暗号化された接続を使用しようとすることを意味します。 これを機能させるには、サーバーでSSLを構成する必要があります。 NginxまたはApacheがすでにこれを行うように構成されている場合、この設定は冗長になることに注意してください。SESSION_COOKIE_SECURE
CookieはHTTPS経由でのみ処理できることをブラウザに通知します。 つまり、プロジェクトがログインなどのアクティビティ用に生成するCookieは、暗号化された接続でのみ機能します。CSRF_COOKIE_SECURE
と同じですSESSION_COOKIE_SECURE
ただし、CSRFトークンに適用されます。 CSRFトークンはクロスサイトリクエストフォージェリから保護します。 Django CSRF保護は、プロジェクトに送信されたフォーム(ログイン、サインアップなど)がサードパーティではなく、プロジェクトによって作成されたことを確認することでこれを行います。SECURE_BROWSER_XSS_FILTER
を設定しますX-XSS-Protection: 1; mode=block
まだ持っていないすべての応答のヘッダー。 これにより、サードパーティがプロジェクトにスクリプトを挿入できないようになります。 たとえば、ユーザーがパブリックフィールドを使用してデータベースにスクリプトを保存している場合、そのスクリプトが取得されて他のユーザーに表示されると、スクリプトは実行されません。
Django内で利用可能なさまざまなセキュリティ設定について詳しく知りたい場合は、ドキュメントを確認してください。
警告: Djangoのドキュメントには、完全に依存すべきではないと記載されています SECURE_BROWSER_XSS_FILTER
. 入力の検証とサニタイズを忘れないでください。
追加の設定
次の設定は、HTTP Strict Transport Security(HSTS)をサポートするためのものです。つまり、サイト全体で常にSSLを使用する必要があります。
SECURE_HSTS_SECONDS
HSTSが設定されている時間(秒単位)です。 これを1時間(秒単位)に設定すると、WebサイトのWebページにアクセスするたびに、次の1時間はHTTPSがサイトにアクセスできる唯一の方法であることがブラウザに通知されます。 その時間中にWebサイトの安全でない部分にアクセスすると、ブラウザにエラーが表示され、安全でないページにアクセスできなくなります。SECURE_HSTS_PRELOAD
次の場合にのみ機能しますSECURE_HSTS_SECONDS
が設定されています。 このヘッダーは、ブラウザにサイトをプリロードするように指示します。 これは、FirefoxやChromeなどの一般的なブラウザに実装されているハードコードされたリストにWebサイトが追加されることを意味します。 これには、Webサイトが常に暗号化されている必要があります。 このヘッダーには注意することが重要です。 プロジェクトで暗号化を使用しないことにした場合はいつでも、HSTSプリロードリストから手動で削除するのに数週間かかる場合があります。SECURE_HSTS_INCLUDE_SUBDOMAINS
HSTSヘッダーをすべてのサブドメインに適用します。 このヘッダーを有効にすると、両方がyour_domain
とunsecure.your_domain
たとえ暗号化が必要になる場合でもunsecure.your_domain
このDjangoプロジェクトとは関係ありません。
警告:これらの追加設定を誤って構成すると、サイトがかなりの時間破損する可能性があります。
これらの設定を実装する前に、HSTSに関するDjangoのドキュメントをお読みください。
これらの設定が独自のDjangoプロジェクトでどのように機能するかを考慮する必要があります。 全体として、ここで説明する設定は、ほとんどのDjangoプロジェクトの優れた基盤です。 次に、のさらなる使用法を確認します dotENV
.
ステップ5—使用 python-dotenv
秘密のために
このチュートリアルの最後の部分は、活用するのに役立ちます python-dotenv
. これにより、プロジェクトのSECRET_KEYや管理者のログインURLなどの特定の情報を非表示にできます。 これらのシークレットは公開されないため、GitHubやGitLabなどのプラットフォームでコードを公開する場合は、これは素晴らしいアイデアです。 代わりに、ローカル環境またはサーバーでプロジェクトを最初にセットアップするときはいつでも、新しいプロジェクトを作成できます。 .env
それらの秘密変数をファイルして定義します。
あなたはあなたを隠す必要があります SECRET_KEY
したがって、このセクションで作業を開始します。
あなたの .env
ファイル:
- nano .env
そして、次の行を追加します。
DJANGO_SETTINGS_MODULE="django_hardening.settings.development"
SECRET_KEY="your_secret_key"
そしてあなたの中で base.py
:
- nano testsite/settings/base.py
更新しましょう SECRET_KEY
そのような変数:
. . .
SECRET_KEY = os.getenv('SECRET_KEY')
. . .
これで、プロジェクトで SECRET_KEY
にあります .env
.
最後に、ランダムな文字の長い文字列を追加して、管理URLを非表示にします。 これにより、ボットがログインフィールドをブルートフォース攻撃したり、見知らぬ人がログインを推測したりすることができなくなります。
開ける .env
また:
- nano .env
そして、 SECRET_ADMIN_URL
変数:
DJANGO_SETTINGS_MODULE="django_hardening.settings.development"
SECRET_KEY="your_secret_key"
SECRET_ADMIN_URL="very_secret_url"
それでは、Djangoに管理者URLを非表示にするように指示しましょう。 SECRET_ADMIN_URL
:
- nano /testsite/urls.py
注:交換することを忘れないでください your_secret_key
と very_secret_url
あなた自身の秘密の文字列で。 また、交換することを忘れないでください very_secret_url
あなた自身の秘密のURLで。
これらの変数にランダムな文字列を使用したい場合、Pythonはそのような文字列を生成するための素晴らしいsecrets.pyライブラリを提供します。 それらが提供するexamplesは、安全なランダム文字列を生成するための小さなPythonプログラムを作成するための優れた方法です。
次のように管理URLを編集します。
import os
from django.contrib import admin
from django.urls import path
urlpatterns = [
path(os.getenv('SECRET_ADMIN_URL') + '/admin/', admin.site.urls),
]
これで、管理者ログインページは次の場所にあります。 very_secret_url/admin/
ただの代わりに /admin/
.
結論
このチュートリアルでは、さまざまな環境で簡単に使用できるように現在のDjangoプロジェクトを構成しました。 あなたのプロジェクトは今活用します python-dotenv
シークレットと設定を処理するため。 また、本番環境では、Djangoの組み込みのセキュリティ機能が有効になっています。
推奨されるすべてのセキュリティコンポーネントを有効にし、指示に従って設定を再実装した場合、プロジェクトには次の主要な機能があります。
- すべての通信(サブドメイン、Cookie、CSRFなど)のSSL/HTTPS。
- XSS(クロスサイトスクリプティング)攻撃の防止。
- CSRF(クロスサイトリクエストフォージェリ)攻撃の防止。
- 隠されたプロジェクトの秘密鍵。
- ブルートフォース攻撃を防ぐ隠された管理者ログインURL。
- 開発と本番用に別々の設定。
Djangoについて詳しく知りたい場合は、Django開発に関するチュートリアルシリーズをご覧ください。
また、プロジェクトをまだ本番環境に移行していない場合は、 Ubuntu 20.04 でPostgres、Nginx、Gunicornを使用してDjangoをセットアップする方法に関するチュートリアルをご覧ください。 その他のチュートリアルについては、Djangoトピックページを確認することもできます。
そしてもちろん、詳細については、Djangoの設定ドキュメントをお読みください。