最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Django中和時區(qū)相關(guān)的安全問題詳解

 更新時間:2020年10月12日 09:26:13   作者:PHITHON  
這篇文章主要給大家介紹了關(guān)于Django中和時區(qū)相關(guān)的安全問題的相關(guān)資料,需要的朋友可以參考下

在開發(fā)國際化網(wǎng)站的時候,難免會與時區(qū)打交道,通用CMS更是如此,畢竟其潛在用戶可能是來自于全球各地的。Django在時區(qū)這個問題上下了不少功夫,但是很多資深的開發(fā)者都有可能尚未完全屢清楚Django中各種時間的實際意義和使用方法,導(dǎo)致寫出錯誤的代碼;作為安全研究人員,時區(qū)問題也可能和一些安全問題掛鉤,比如優(yōu)惠券的過期時間、訂單的下單與取消時間等,如果沒有考慮時區(qū)問題,有可能將導(dǎo)致一些邏輯漏洞。

本文就從多個常用模塊開始,了解一下Django中的時區(qū)究竟是怎么回事,以及在時間的比較中可能出現(xiàn)的一些邏輯錯誤。

從“兩種時間”說起

我們都知道,在Python中表示“時間”的對象是datetime.datetime。

其實在Python中,這個對象被分成了兩個類型:

  • aware datetime
  • naive datetime

他們的區(qū)別是:如果datetime對象的tzinfo屬性有設(shè)置時區(qū)值,則這個對象是一個aware datime;否則它是一個naive datetime。

舉個例子,我們平時在編寫Python腳本的時候,使用下面這行代碼獲取當(dāng)前時間:

from datetime import datetime
t = datetime.now()

此時,t是一個naive datetime,因為我們沒有給他設(shè)置時區(qū):

image-20201011010557126.png

naive的中文意思大家應(yīng)該都很熟悉,這里的大概意思就是“simple”,這是一個很簡單、原始的時間對象。實際上就是指,計算機不知道這個時間,他的時區(qū)究竟是什么,它可能代表著北京時間,也可能是UTC時間,因為我們沒有指定時區(qū),我們無法“假設(shè)”其是計算機系統(tǒng)所在的時區(qū),也無法“假設(shè)”其是UTC時區(qū)。也就是說,計算機拿到了一個naive datetime,是無法準(zhǔn)確地定位到某一個時間點的,也無法直接轉(zhuǎn)換成一個unix時間戳。

那么相對的,aware datetime就是計算機能準(zhǔn)確知道其時區(qū)的時間對象,他是一個準(zhǔn)確的時間點,就落在時間軸上的某個地方,不管從哪個時區(qū)看,這個點都是絕對固定的。所以,我們可以將一個aware datetime轉(zhuǎn)換成unix時間戳。

有的同學(xué)可能比較好奇,你說naive datetime無法轉(zhuǎn)換成時間戳,那么為什么這個對象有一個timestamp()方法呢:

image-20201011012655581.png

原因我們查文檔可以得出結(jié)論,如果對象是naive datetime,則會以當(dāng)前系統(tǒng)本地時區(qū)為準(zhǔn)。

Django的時區(qū)配置

回到Django。由于Django是一個國際化框架,時區(qū)相關(guān)處理自然是其必不可少的組成部分。Django的配置項中,有下面兩個選項與時區(qū)相關(guān):

  • USE_TZ
  • TIME_ZONE

USE_TZ用來指定整個項目是否使用時區(qū),TIME_ZONE是默認(rèn)時區(qū)的值。

如果USE_TZ的值設(shè)置為False,那么Django項目中所有時間都使用naive datetime(除非有明確指定時區(qū)的情況)。也就是說,網(wǎng)站內(nèi)存儲和使用的時間全部是TIME_ZONE的值所指定的時區(qū)。

這樣做有一些弊端:

  • 數(shù)據(jù)庫中保存的是naive datetime,導(dǎo)致在跨區(qū)域遷移數(shù)據(jù)的時候,可能無法準(zhǔn)確定位到某個時間點
  • 國際化企業(yè)可能面向不同國家有不同的網(wǎng)站,但后臺數(shù)據(jù)庫相同,此時究竟使用哪個時區(qū)保存和展示時間,將引起混亂
  • 即使是同一個網(wǎng)站的用戶,他們可能來自于全球各地,查看到的時間卻是統(tǒng)一的服務(wù)器時間,對于高交互式的應(yīng)用十分不友好
  • 即使網(wǎng)站面向的用戶僅來自于某一個地區(qū),也會涉及到“夏時令”(Daylight Saving Time)相關(guān)的問題,每年可能將會導(dǎo)致兩次時間誤差

默認(rèn)情況下,用django-admin生成的項目,其設(shè)置中USE_TZ等于True,這也是Django官方建議的配置。此時,在網(wǎng)站內(nèi)部存儲與使用的是UTC時間,而與用戶交互時使用TIME_ZONE或手工的時區(qū)。

我們后文中也以Django的默認(rèn)配置USE_TZ=True為前提條件,否則也沒有討論的必要了。

Django的時間函數(shù)

Django的包django.utils.timezone中有下面幾個常用的時間相關(guān)函數(shù):

  • now(),返回當(dāng)前的UTC時間
  • localtime(),返回當(dāng)前的本地時間(默認(rèn)是TIME_ZONE配置指定的時區(qū)時間)
  • is_aware(),傳入的時間是否是aware datetime
  • is_naive(),傳入的時間是否是naive datetime
  • make_aware(),將naive時間轉(zhuǎn)換成aware時間
  • make_naive(),將aware時間轉(zhuǎn)換成naive時間

因為開啟了USE_TZ,Django內(nèi)部操作時間時都應(yīng)該使用aware時間,否則會出現(xiàn)異常。所以,我們在獲取當(dāng)前時間的時候,一定要使用Django自帶的now()localtime()函數(shù),而不能使用Python的datetime.datetime.now()函數(shù)。

數(shù)據(jù)庫存儲的時間

我們在使用ORM的DatetimeField時,常常會有這樣的疑慮:我們究竟應(yīng)該給DatetimeField傳入哪個時區(qū)的時間呢?

可以做個試驗,編寫下面這個model:

class Archive(models.Model):
  title = models.CharField('title', max_length=256)

  now_time = models.DateTimeField(default=timezone.now)
  local_time = models.DateTimeField(default=timezone.localtime)

這個model有三個屬性,title是他的名字,now_time和local_time是兩個時間,他們的默認(rèn)值分別是timezone.now和timezone.localtime。

也就是說,默認(rèn)情況下,now_time字段傳入的是UTC時區(qū)的當(dāng)前時間,local_time字段傳入的是本地時區(qū)的當(dāng)前時間,我這里是Asia/Shanghai。

然后,我們創(chuàng)建一個Archive對象:

image-20201011024130489.png

可以發(fā)現(xiàn),不管我們使用a.now_time還是a.local_time,讀取到的datetime對象的tzinfo都是UTC。

這也印證了Django文檔中說到的,不管傳入的時間對象時區(qū)是什么,其內(nèi)部存儲的時間均為UTC時區(qū)。但是,值得注意的是,如果我們傳入了一個不帶時區(qū)的naive datetime,將會出現(xiàn)一個警告,并使用默認(rèn)時區(qū)填充其tzinfo:

image-20201011024854993.png

模板中展示的時間

對于網(wǎng)站的用戶來說,他們想看到的時間顯然不是UTC時間,而是某一個具體時區(qū)的時間。比如,我的網(wǎng)站幾乎全部是中國用戶,那么展示時使用的時區(qū)應(yīng)該是Asia/Shanghai。

這一部分的轉(zhuǎn)換,Django放在的模板引擎中。

Django在渲染模板變量時,將會遇到兩種與時間有關(guān)的情況:

<p>origin value: {{ object.now_time }}</p>
<p>date filter: {{ object.now_time | date:'Y-m-d H:i:s' }}</p>

前者是直接將時間渲染到頁面中,后者是通過date這樣的模板filter處理后渲染在頁面中。這兩種情況在內(nèi)部處理方式略有不同此處不細(xì)表,總體而言,任意模板中變量的渲染,都會被轉(zhuǎn)換時區(qū)。

那么,脫離模板引擎,我們會得到怎樣的結(jié)果呢?

在流行的前后端分離架構(gòu)中,后端服務(wù)器通常只提供JSON格式的接口給前端,那么,我們編寫下面這樣一個view,看看返回值是什么:

from django.shortcuts import get_object_or_404
from django.http.response import JsonResponse
from django.utils import timezone

from . import models


def json(request):
  object = get_object_or_404(models.Archive, pk=1)
  data = dict(
    id=object.pk,
    now_time=object.now_time,
    local_time=timezone.localtime(object.local_time)
  )
  return JsonResponse(data=data)

返回對象的now_time,我直接將object.now_time返回;返回對象的local_time,我將數(shù)據(jù)庫值轉(zhuǎn)換成本地時間timezone.localtime(object.local_time)返回。

我前文說過,這兩個值在數(shù)據(jù)庫中的值是完全相等的,不過在json返回中,now_time是UTC時間,而local_time是北京時間:

image-20201011031507193.png

也就是說,在前后端分離的網(wǎng)站中,如果直接使用Model的字段,那么前端需要負(fù)責(zé)進行時區(qū)的轉(zhuǎn)換,否則將會出現(xiàn)時間的偏差。

時間的校驗和比較

在一些業(yè)務(wù)場景下,我們可能會涉及到時間的校驗和比較,如:

  • 付費服務(wù)、商品、用戶的有效期檢查
  • 活動的開始與結(jié)束時間檢查
  • 訂單、商品的收貨、取消時間檢查

我們就以付費用戶為例:用戶購買了30天的VIP會員,我們需要給用戶表中設(shè)置一個過期時間,比如下面這個model。

from django.db import models
from django.utils import timezone

class Account(models.Model):
  username = models.CharField(max_length=256)
  password = models.CharField(max_length=64)

  created_time = models.DateTimeField(default=timezone.now)
  expired_time = models.DateTimeField()

如果某個用戶某一個時刻對網(wǎng)站進行訪問,我們?nèi)绾闻袛嗨欠窬哂蠽IP權(quán)限呢?

通常情況下我們有兩種常見的判斷方法。一是,用戶訪問時,直接從model中取出這個對象,然后和now()進行比較:

image-20201011033452219.png

這種情況下,當(dāng)前時間不管是now()還是localtime()都不影響比較的結(jié)果,因為兩個datetime對象在比較時會考慮時差。

另一種情況是,通過ORM的queryset進行比較,等于在數(shù)據(jù)庫層面進行操作:

if models.Account.objects.filter(expired_time__gt=timezone.now()).exists():
  # doing sth

image-20201011034352025.png

Django也幫我們考慮過這種情況,即使此時我們使用本地時間timezone.localtime()進行查詢,系統(tǒng)也會將其轉(zhuǎn)換成UTC時間傳入SQL語句:

image-20201011034633005.png

但是,如果我們使用到了和日期、時間有關(guān)的lookups,將產(chǎn)生相反的結(jié)果。

怎么理解這個問題呢,我們還是來舉個例子。比如,網(wǎng)站以用戶注冊當(dāng)天的日子作為“會員日”(比如1月2日注冊的會員,以后每月的2日都是他的會員日),會員日這一天會給這個用戶贈送優(yōu)惠券。

那么,發(fā)送優(yōu)惠券時,我們?nèi)绾魏Y選網(wǎng)站內(nèi)會員日是今日的所有用戶?

下面這個filter是否正確?

models.Account.objects.filter(created_time__day=timezone.now().day).all()

答案是否定的,我們應(yīng)該使用timezone.localtime()表示今天,而非timezone.now()

models.Account.objects.filter(created_time__day=timezone.localtime().day).all()

這是為什么呢?你不是說數(shù)據(jù)庫中存儲的都是UTC時間嗎,為何會使用到timezone.localtime()

原因是,Django在使用日期、時間有關(guān)的lookups時,會在數(shù)據(jù)庫層面對時間進行時區(qū)的轉(zhuǎn)換再進行比較,所以我們需要使用本地時間而不是UTC時間。

可以看看原始的SQL語句:

image-20201011041652087.png

可見,SQL語句中使用了django_datetime_extract('day', "sample_account"."created_time", 'Asia/Shanghai', 'UTC')將UTC時間轉(zhuǎn)換成了北京時間,因此后面比較的時候,也應(yīng)該使用北京時間。

這一點需要格外注意。時間比較的不謹(jǐn)慎,說小點是一個Bug,說大點就是漏洞,畢竟很多涉及到時間比較的情景,都是非常需要嚴(yán)謹(jǐn)?shù)摹?/p>

所以,我們總結(jié)一下:

  • 任何比較都使用aware時間,不能使用naive時間
  • 時間屬性直接比較時,使用任何aware時間均可(會被自動轉(zhuǎn)換成UTC)
  • queryset查詢,不涉及__day、__date、__year等時間lookups時,使用任何aware時間均可(會被自動轉(zhuǎn)換成UTC)
  • queryset查詢,涉及到時間lookups時,使用本地時間

到此這篇關(guān)于Django中和時區(qū)相關(guān)的安全問題詳解的文章就介紹到這了,更多相關(guān)Django時區(qū)安全問題內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Django中的Model操作表的實現(xiàn)

    Django中的Model操作表的實現(xiàn)

    這篇文章主要介紹了Django中的Model操作表的實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07
  • Python中的套接字編程是什么?

    Python中的套接字編程是什么?

    不可否認(rèn),互聯(lián)網(wǎng)已成為“存在之魂”,其活動以“連接”或“網(wǎng)絡(luò)”為特征.使用套接字的最關(guān)鍵的基礎(chǔ)之一,使這些網(wǎng)絡(luò)成為可能.本文涵蓋了有關(guān)使用Python進行套接字編程的所有領(lǐng)域.套接字可以幫助您建立這些連接,而Python無疑可以簡化連接,需要的朋友可以參考下
    2021-06-06
  • Python自動爬取圖片并保存實例代碼

    Python自動爬取圖片并保存實例代碼

    大家好,本篇文章主要講的是Python自動爬取圖片并保存實例代碼,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • python數(shù)組排序方法之sort、sorted和argsort詳解

    python數(shù)組排序方法之sort、sorted和argsort詳解

    這篇文章主要給大家介紹了關(guān)于python數(shù)組排序方法之sort、sorted和argsort的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2022-03-03
  • Python 面向?qū)ο?成員的訪問約束

    Python 面向?qū)ο?成員的訪問約束

    在Java,C++,以及PHP中都有對應(yīng)的關(guān)鍵字,public,protected,private,但是在Python中卻沒有這些關(guān)鍵字來聲明類成員的訪問作用域。
    2008-12-12
  • Python實現(xiàn)釘釘/企業(yè)微信自動打卡的示例代碼

    Python實現(xiàn)釘釘/企業(yè)微信自動打卡的示例代碼

    這篇文章主要介紹了Python實現(xiàn)釘釘/企業(yè)微信自動打卡的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • 一文詳細(xì)介紹Python中pkl格式文件

    一文詳細(xì)介紹Python中pkl格式文件

    .pkl文件是Python中用于存儲對象的文件格式,全稱是"pickle",它是Python標(biāo)準(zhǔn)庫中的一個模塊,用于將Python對象序列化,以便于在不同的Python程序之間進行傳輸或存儲,這篇文章主要給大家介紹了如何通過一文詳細(xì)介紹Python中pkl格式文件的相關(guān)資料,需要的朋友可以參考下
    2024-05-05
  • Python實現(xiàn)TXT數(shù)據(jù)轉(zhuǎn)三維矩陣

    Python實現(xiàn)TXT數(shù)據(jù)轉(zhuǎn)三維矩陣

    在數(shù)據(jù)處理和分析中,將文本文件中的數(shù)據(jù)轉(zhuǎn)換為三維矩陣是一個常見的任務(wù),本文將詳細(xì)介紹如何使用Python實現(xiàn)這一任務(wù),感興趣的小伙伴可以了解下
    2024-01-01
  • 自定義django admin model表單提交的例子

    自定義django admin model表單提交的例子

    今天小編就為大家分享一篇自定義django admin model表單提交的例子,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-08-08
  • PyCharm設(shè)置Ipython交互環(huán)境和宏快捷鍵進行數(shù)據(jù)分析圖文詳解

    PyCharm設(shè)置Ipython交互環(huán)境和宏快捷鍵進行數(shù)據(jù)分析圖文詳解

    這篇文章主要介紹了PyCharm設(shè)置Ipython交互環(huán)境和宏快捷鍵進行數(shù)據(jù)分析圖文詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04

最新評論

乐至县| 尚志市| 迁西县| 达拉特旗| 湄潭县| 营口市| 新田县| 高阳县| 罗山县| 额尔古纳市| 什邡市| 秦皇岛市| 离岛区| 瑞金市| 舒兰市| 阳山县| 科尔| 宁蒗| 本溪| 怀化市| 封丘县| 安丘市| 延寿县| 锦屏县| 新干县| 大竹县| 钟山县| 历史| 鄂托克旗| 南昌县| 鄱阳县| 玛纳斯县| 松阳县| 墨竹工卡县| 彭水| 恩施市| 杂多县| 衡水市| 蛟河市| 于都县| 遂平县|