2020年6月3日に修正されたDjangoの脆弱性CVE-2020-13254・CVE-2020-13596について解説します。
公式サイトでのリリース情報は以下を参照してください。
Django security releases issued: 3.0.7 and 2.2.13 | Weblog | Django
影響を受けるバージョン
以下のバージョンが影響を受けます。
- Django master branch
- Django 3.1
- Django 3.0
- Django 2.2
脆弱性の内容
CVE-2020-13254: Potential data leakage via malformed memcached keys
memcachedを使っている場合に、不正なキーを渡すことでデータの漏洩を起こす可能性があります。
CVE-2020-13596: Possible XSS via admin ForeignKeyRawIdWidget
ForeignKeyRawIdWidget
がadmin上で生成するクエリパラメータにXSS脆弱性があります。
この脆弱性は、モデルにForeignKey.limit_choices_to・ManyToManyField.limit_choices_toを指定したフィールドがある場合に発生する可能性があります。
脆弱性を利用した攻撃の例
サンプルコードで使っている環境のバージョンは以下の通りです。
- Django 3.0.6
- pylibmc 1.6.1
- Python 3.8.3
- memcached 1.6.6
- libmemcached 1.0.18
CVE-2020-13254: Potential data leakage via malformed memcached keys
まず、公式ドキュメントに従ってsettings.py
を編集します。以下が設定例です。
|
|
次に、shell
コマンド上で以下を実行します。
|
|
最後のcache.get('my_key' + c)
はNone
が返ってくるはずですが、'my_key'
キーで設定された値'hello, world!'
を取得できてしまいました。
CVE-2020-13596: Possible XSS via admin ForeignKeyRawIdWidget
以下のコードを用意します。
example/models.py
|
|
example/admin.py
|
|
makemigrations
コマンド・migrate
コマンドでデータベースを作成し、createsuperuser
コマンドでadminユーザーを作成してください。
shell
コマンドで以下のデータも作っておきます。
|
|
runserver
コマンドで開発サーバーを立ち上げ、以下URLからUnsafeLimitChoicesTo
を作成します。Band
は1
を指定してください。
http://127.0.0.1:8000/admin/example/unsafelimitchoicesto/add/
登録後のデータを表示して、以下の虫眼鏡ボタン(赤枠部分)のHTMLを確認してみましょう。
以下のように"&><escapeme
の部分がエスケープされずに埋め込まれています。
|
|
limit_choices_to
を'"></a><script>alert(\'XSS\');</script><a href="'
のような値にすれば、adminにスクリプトを仕込むことも可能です。
どのコードに問題があったか・どのように修正されたか
実際の変更内容は以下のGitHubコードを参照してください。
CVE-2020-13254:
- On the master branch
- On the 3.1 release branch
- On the 3.0 release branch
- On the 2.2 release branch
CVE-2020-13596:
- On the master branch
- On the 3.1 release branch
- On the 3.0 release branch
- On the 2.2 release branch
CVE-2020-13254: Potential data leakage via malformed memcached keys
django.core.cache.backends.memcached.BaseMemcachedCache
ではmemcachedにキーを渡す際に入力値をそのまま渡していました。
そこで、validate_key
メソッドを追加して入力値を検査し、不正な値が含まれている場合はmemcachedにキーを渡さず、警告メッセージを出力させるようになりました。
Django 3.0.7で先述の「脆弱性を利用した攻撃の例」に載せたコードを実行すると、以下のメッセージが表示されます。
|
|
CVE-2020-13596: Possible XSS via admin ForeignKeyRawIdWidget
django.contrib.admin.widgets.ForeignKeyRawIdWidget.get_context
の中で、related_url
変数(limit_choices_to
の値を虫眼鏡ボタンに埋め込むために使う)にdjango.utils.safestring.mark_safe
を使った値を渡していたことが原因でした。django.utils.safestring.mark_safe
を使った値はテンプレート上でエスケープされません。
修正後のコードではdjango.utils.safestring.mark_safe
を使わずdjango.utils.http.urlencode
を使うようになりました。
Django 3.0.7で先述の「脆弱性を利用した攻撃の例」に載せたコードを実行すると、"&><escapeme
がエスケープされるようになります。
|
|