
Djangoのannotate()およびalias()メソッドにおける動的エイリアスを介したSQLインジェクション(CVE-2025-57833)を示す教育用概念実証。脆弱なコード、悪用例、修正分析を含みます。
エイリアスとは、SQLクエリ内の列または集計結果に付けられる名前です。
Djangoでは、annotate() または alias() メソッドで計算フィールドに名前を付けるためにエイリアスが使用されます。
例:
from django.db.models import Count
books = Book.objects.annotate(book_count=Count('id'))
ここで、book_count は Count('id') の結果に対するエイリアスです。
これにより、計算された列に分かりやすい名前を取得できます。
手早く済ませるために、シェル経由でデータを挿入できます:
python manage.py shell
実行するコマンド:
from myapp.models import Author, Book
a = Author.objects.create(name=" houchi pierre")
Book.objects.create(title="Les belles filles", author=a)
Book.objects.create(title="Les baux arcons", author=a)
exit()
Django 4.2.23 より前では、ユーザーが提供した動的エイリアスを介してSQLを注入することが可能でした。
この脆弱性は CVE-2025-57833 として知られています。
この脆弱性は、**kwargs で展開される辞書が、ユーザー由来のフィルタリングされていないキーとともに使用された場合に、annotate() 関数と alias() 関数に影響を与えました。
myapp/views.py)import json
from django.db.models import Count
from django.http import JsonResponse
from .models import Author
def vulnerable_view(request):
# On récupère l'alias depuis l'URL
alias_param = request.GET.get("alias", "{}")
try:
# ⚠️ Vulnérable : évaluation directe des données utilisateurs
alias_dict = json.loads(alias_param)
for key, value in alias_dict.items():
alias_dict[key] = eval(value) # dangereux ! permet l'exécution de code arbitraire
# Création de la queryset avec annotation dynamique
qs = Author.objects.annotate(**alias_dict).values("name", *alias_dict.keys())
# Retour des résultats
return JsonResponse(list(qs), safe=False)
except Exception as e:
return JsonResponse({"error": str(e)})
alias_param = request.GET.get("alias", "{}")
ユーザーによって渡された alias パラメータの値を取得します。
alias_dict = json.loads(alias_param)
JSON文字列をPythonの辞書に変換します。
alias_dict[key] = eval(value)
⚠️ 非常に危険:eval() は文字列をPythonコードとして実行します。
ユーザーは破壊的なSQLを注入できる可能性があります。
Author.objects.annotate(**alias_dict)
提供されたエイリアスを使用してアノテーションを動的に適用します。
myapp/models.py)from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
def __str__(self):
return self.title
説明:
Author と Book は ForeignKey リレーションで関連付けられています。Author に対して使用され、その書籍に関する情報を計算します。http://127.0.0.1:8000/vuln/?alias={"evil); DROP TABLE myapp_book;--":"Count('id')"}
Django は今後、エイリアス内の特定の文字を禁止します:
--)URLにこれらの文字が含まれる場合、Django はエラーを発生させます:
Column aliases cannot contain whitespace characters, quotation marks, semicolons, or SQL comments.
http://127.0.0.1:8000/vuln/?alias={"books_count":"Count('book')"}
eval()。eval() を決して使用しない。著者: Loïc
日付: 06/09/2025