この記事は以下のターゲットを対象としています。
★5 Djangoの開発経験が3年以上。
★4 Djangoの開発経験が1年以上。
★3 WEBサイト開発経験あり。これからDjangoを学習します。
★2 Python初級者。簡単なプログラムコードが書けます。
★1 プログラミング未経験。
こんにちは、グローバルウェイの清家です。
今回はグローバルウェイの開発標準とするDjangoに関するノウハウを紹介します。
Djangoのセキュリティについて考える
DjangoはフルスタックのWEBアプリケーションフレームワークです。クロスサイトスクリプティング(XSS)、クロスサイトリクエストフォージェリ(CSRF)、SQLインジェクションなど、基本的なWEBアプリケーションに必要なセキュリティ対策が組み込まれています。但し、正しい使い方を知らなければ、セキュリティリスクの温床になってきます。
そこで、「Djangoのセキュリティについて考える」と題し、シリーズ化して記事をお届けします。
クロスサイトスクリプティングとは?
WEBアプリケーションでは、WEBブラウザ上にさまざまな情報を表示します。その表示方法に適切な対応がなされていない場合、攻撃者は他のユーザーに対して、URLリンクを踏ませることによってWEBアプリケーション上で悪意のあるスクリプトコードを実行させることができます。その結果、クッキー、セッションIDなどの情報が盗まれたり、悪意のある操作が実行されたりします。開発者は入力項目のバリデーションや、出力項目に対して、正しくサニタイズ処理を行う必要があります。
Djangoにおける対策方法
DjangoにはTemplateエンジンの機能が備わっています。Templateエンジンは、htmlなどの静的なWEBページ内にコードを書くことでサーバで処理した値を動的に表示できます。WEBページ生成時にTemplateを使用することで、スクリプトコードで使用する特殊な記号(”<”, “>”, “””など)に対して、サニタイズ処理を自動的に行います。
以下にサンプルコードを示します。
ユーザーがスクリプトコードを含む文字列を画面に表示します。
“<script>alert(‘xss’);</script>”がサニタイズ処理されていることがわかります。
View(python)
return render(request, “sample.html”, {“data”: “<script>alert(‘xss’);</script>”})
Template(html)
<body>
<div>{{ data }}</div>
</body>
※サニタイズ処理は、「ブラウザ上→右クリック→ページのソースを表示」から確認できます。
<body>
<div><script>alert('XSS');</script></div>
</body>
Templateだけでは防げない①
実装方法によっては、Templateを正しく使用しなければ防げないケースも出てきます。
以下のサンプルコードでは、button要素のclassにスクリプトコードを埋め込みます。”{{ }}”で囲っているにもかかわらず、正しくサニタイズ処理がされず、ボタンに対して、マウスオーバーをするとスクリプトが実行されることが確認できます。
View(python)
return render(request, “sample.html”, {“xss_code”: “class1 onmouseover=javascript:alert('XSS');
”})
Template(html)
<body>
<div><button class={{ xss_code }}>ボタン</button></div>
</body>
classを使用する場合、以下のようにダブルクォーテーションで囲むことで正しくサニタイズ処理がなされます。
Template(html)
<body>
<div><button class=”{{ xss_code }}”>ボタン</button></div>
</body>
Templateだけでは防げない②
WEBアプリケーションを構築する上でJavaScriptを使用する機会が多くなります。ここではJavaScriptのライブラリであるjQueryによる画面を表示する例を示します。以下のサンプルコードでは、Ajaxによる非同期処理で取得した値で画面を描画します。サニタイズ処理がされることなく、スクリプトが実行されることを確認できます。
View(python)
return JsonResponse({“xss_code”: “<script>alert('XSS');</script>”})
Template(html)
// jQueryによる操作
<script>
// Ajax
$(function () {
$.ajax({
type: "GET",
url: "スクリプトを返すURL"
}).done(function (data, textStatus, jqXHR) {
$('#xss_code').html(data['xss_code']);
})
});
</script>
<body>
<div id=”xss_code”></div>
</body>
以下のようにtext関数を使用することでサニタイズ処理がされます。
Template(html)
// jQueryによる操作
・・・省略・・・
$('#xss_code').text(data['xss_code']);
・・・省略・・・
<body>
<div id=”xss_code”></div>
</body>
サニタイズを回避するには
これまでは特殊な記号に対するサニタイズについて、説明してきました。しかし実装する上で特殊な記号をサニタイズすることなく、html要素として出力したいケースがあると思います。Templateには組み込みタグとフィルタが用意されており、以下のように実装することで、html要素として出力されます。但し、設定した表示項目がクロスサイトスクリプティングの危険性がないことを十分に注意した上で使用してください。
Template(html)
<!-- autoescapeタグで変数を囲むことでhtml要素として出力します。 -->
{% autoescape off %}
{{ data }}
{% endautoescape %}
Template(html)
<!-- safeフィルタをパイプでつなげることでhtml要素として出力します。 -->
{{ data | safe }}
まとめ
Djangoにおけるクロスサイトスクリプティングの対策について説明してきました。しかし今回挙げた対策はほんの一部となります。例えば、レスポンスヘッダの脆弱性を狙ってクロスサイトスクリプティングのリスクを招く攻撃など、攻撃の種類も多種多様なものになってきます。次回以降もまた、DjangoにおけるWEBアプリケーションのセキュリティリスクを取り上げ対策を説明したいと思います。
参考文献
https://docs.djangoproject.com/ja/4.2/topics/security/#cross-site-scripting-xss-protection