見出し画像

DjangoでのCross-Site Scripting(XSS)防止の適用


Web 開発では、クロスサイト スクリプティング (XSS) は一般的なセキュリティ脆弱性であり、攻撃者が被害者のブラウザで悪意のあるスクリプトを実行することを可能にする。強力で人気のある Python Web フレームワークである Django は、開発者が XSS 攻撃から効果的に保護できるようにするさまざまなメカニズムを提供していうr。この記事では、Django アプリケーションにXSS攻撃に対する保護を実装する方法について紹介する。

1.Cross-Site Scripting (XSS) 攻撃

XSS 攻撃はあるユーザーに対してクライアント用のスクリプトを別のユーザーのブラウザに読み込ませることを可能にしてしまいます。この攻撃は通常他のユーザーに対して選択・表示を行うデータベース内に悪意のあるスクリプトを保存させる、あるいは攻撃者の JavaScript がブラウザで実行されるリンクをユーザーにクリックさせることでなされます。しかしながら、XSS 攻撃はページを読み込む前に十分なサニタイズを行っていなければ、信頼できないクッキーやウェブ・サービスのようなデータが発生の原因となることがあります。

https://docs.djangoproject.com/ja/5.1/topics/security/

HTML は、一部の文字を特別に扱うことでテキストとマークアップを区別するハイパーテキスト マークアップ言語である。たとえば、< は HTML タグの先頭とみなされ、<title> と </title> の間の文字はページのタイトルなどと見なされる。

動的ページに挿入されたコンテンツにこれらの特殊文字 (< など) が含まれている場合、ユーザーのブラウザは HTML タグを挿入したものと誤認し、これらの HTML タグが JavaScript スクリプトを導入すると、これらのスクリプトがユーザーのブラウザで実行されます。 したがって、これらの特殊文字を動的ページでチェックできない場合、またはチェックでエラーが発生した場合、XSS 脆弱性が発生する。

XSS 攻撃の中核は、攻撃者が Web アプリケーションに悪意のあるスクリプトを挿入し、被害者のブラウザで実行できること。これらのスクリプトは、ユーザーの機密情報を盗んだり、悪意のあるアクションを実行したり、被害者のブラウザを完全に制御したりする可能性がある。

調査によると、近年 XSS はバッファ オーバーフローを上回り、最も一般的な攻撃手法となり、Web サイトの 68% がそのような攻撃の被害に遭っている可能性がある。

Open Web Application Security Project が発表した 2010 年の統計によると、Web セキュリティの脅威トップ 10 の中で、XSS はコード インジェクション (Injection) に次いで 2 位にランクされている。

2.Django XSS 防止

2.1 自動エスケープ

Django の Template Engine、HTML タグと特殊文字を自動的にエスケープし、悪意のあるスクリプトがテンプレート内で実行されるのを防ぐ。つまり、ユーザーが入力したコンテンツがテンプレートに直接挿入されると、Django はその中の HTML タグを対応するエンティティ文字に自動的に変換し、攻撃者が悪意のあるスクリプトを挿入することを防ぐ。

ユーザーが指定したデータをテンプレートでレンダリングすると、Django は HTML 特殊文字 (<、>、'、" など) を安全な文字列に自動的にエスケープする。

{% for comment in comments %}
    <p>{{ comment.text }}</p>
{% endfor %}

2.2 手動でエスケープを無効にする

場合によっては、自動エスケープを無効にする必要がある場合があるが、データが安全であることが十分に確信できない限り、多くの場合は危険

<p>{{ comment.text|safe }}</p>

2.3 手動でエスケープを有効にする

{% autoescape off %}
    {{ comment.text|escape }}
{% endautoescape %}

2.4 安全な文字列

Django は、文字列を安全であるとマークするために使用され mark_safe 関数を提供する。つまり、自動エスケープを必要としない。この関数を慎重に使用する必要がある。

mark_safe は主に次の状況で使用さる。

  • テンプレートに HTML タグを含むコンテンツを出力する必要があるが、それらをエスケープしたくない。

  • 信頼できるソース (管理者からの手動入力など) から HTML コンテンツを取得し、それをテンプレートで直接レンダリングしたい。

# エスケープしたい
content = "<strong>文字</strong>"
# 出力結果:&lt;strong&gt;文字&lt;/strong&gt;

# エスケープしたくない
from django.utils.safestring import mark_safe

content = mark_safe("<strong>文字</strong>")
# 出力結果;文字

安全上の注意事項

  • XSS 攻撃につながる可能性があるため、ユーザーが入力したデータでは mark_safe を使用しないでください。

  • ユーザーが入力したデータに対して mark_safe を使用すると、攻撃者が悪意のある JavaScript コードを挿入する可能性がある。

2.5 JavaScript へのユーザーデータの埋め込みを避ける

ユーザー入力を JavaScript に埋め込む必要がある場合は、Django の json_script タグを使用して入力が安全であることを確認できる。

<script type="application/json" id="user-data">
    {{ user_data|json_script:"user-data" }}
</script>

JavaScript 経由でこのデータを安全に読み取る。

const userData = JSON.parse(document.getElementById('user-data').textContent);

2.6 CSP (Content Security Policy)

Django CSP は、Django Web サイトにコンテンツ セキュリティ ポリシー (CSP) を実装するのに役立つオープン ソースの Django アプリケーションである。

Content Security Policyは、特定の種類のクロスサイト スクリプティングおよびクリックジャッキング攻撃を防止する Web セキュリティ ポリシーである。ブラウザがロードできるソースを指定することにより、script、style、またはimmageなど)を使用すると、Web サイトが潜在的な攻撃者にさらされる攻撃対象領域を制限できる。

Django の Response Header に CSP ルールを追加し、特定のドメイン名のスクリプトとスタイルのみを許可するように指定できる。これにより、XSS 攻撃を効果的に防止できる。

CSP は Django のミドルウェアを通じてセットアップできる。

pip install django-csp

# settings.py
INSTALLED_APPS = [
 # ...
 'csp',
]

MIDDLEWARE = [
    'csp.middleware.CSPMiddleware',
    # ...
]

CSP_DEFAULT_SRC = ("'self'",)
CSP_SCRIPT_SRC = ("'self'", "'unsafe-inline'", "'unsafe-eval'",)
CSP_IMG_SRC = ("'self'", "data:", "'unsafe-inline'",)
CSP_STYLE_SRC = ("'self'", "'unsafe-inline'",)
CSP_CONNECT_SRC = ("'self'",)
CSP_FONT_SRC = ("'self'",)
CSP_FRAME_ANCESTORS = ("'self'",)
CSP_REPORT_URI = "/csp-report/"

{% csp %} を HTML Templateに追加し、これにより、CSP Header情報が HTTP Reponseに自動的に挿入される。

3.参考文献

いいなと思ったら応援しよう!