国产一区二区精品久久_蜜桃狠狠狠狠狠狠狠狠狠_午夜视频精品_激情都市一区二区

當(dāng)前位置:首頁 > 網(wǎng)站舊欄目 > 學(xué)習(xí)園地 > 設(shè)計軟件教程 > 翻譯www.djangobook.com之第二十章:安全

翻譯www.djangobook.com之第二十章:安全
2010-01-14 06:59:45  作者:  來源:
internet是令人驚恐的地方
在過去的幾年里,internet恐怖故事幾乎持續(xù)出現(xiàn)在新聞中,我們看到病毒以驚人的速度傳播,大量危及安全的計算機被當(dāng)
作武器,從未結(jié)束的武裝與垃圾郵件作戰(zhàn),以及許多從危及安全的網(wǎng)站鑒別盜竊的報導(dǎo)

作為好的web開發(fā)人員,打擊這些黑暗勢力是我們的責(zé)任,每個web開發(fā)人員需要把安全作為基本的web編程方面,不幸的是,
安全問題看起來很棘手--攻擊者只需要找到一個單獨的弱點,但是防御者必須保護每個單獨的方面

Django嘗試減輕這個難點,它設(shè)計來自動為你防護許多常見的新手(甚至有經(jīng)驗的)web開發(fā)人員容易犯的安全錯誤,理解這些
問題是什么仍然很重要,Django怎樣保護你,以及--更重要的--你讓你的代碼更安全的步驟
但是,首先,一個重要的不承諾:我們決不是這個領(lǐng)域的專家,所以我們不會嘗試全面的解釋每個弱點,相反,我們將給出適
合Django的安全問題的一個簡短的大綱

web安全的主題
如果你只從本章學(xué)習(xí)到一件事情,則讓它為這個:
從不--在任何情況下--信任瀏覽器的數(shù)據(jù)
你從來不知道在HTTP連接的另一端是誰,它可能是一個你的用戶,但是它也可能很容易為一個尋找漏洞的攻擊者或小腳本
來自于瀏覽器的任何類型的數(shù)據(jù)需要被當(dāng)作是偏執(zhí)狂的一副健康良藥,它保護"in band"的數(shù)據(jù)--即從web表單提交的數(shù)據(jù)--
和"out of band"--即HTTP頭部,cookies,以及其他請求信息,欺騙通常瀏覽器自動添加的請求元數(shù)據(jù)是很微不足道的
本章討論的每個弱點都直接來自于信任來自于線上的數(shù)據(jù)然后在使用它之前清除數(shù)據(jù)失敗,你應(yīng)該讓不斷的問"數(shù)據(jù)來自于何
處?"成為一般實踐

SQL注射
SQL注射是一個常見的開拓,攻擊者改變Web頁面參數(shù)(例如GET/POST數(shù)據(jù)或URLs)來插入天真的Web程序直接在它的數(shù)據(jù)庫執(zhí)行
的任意的SQL片段,這可能是在瘋狂世界里最危險的--不幸的是它是最常見的--弱點
這個弱點最容易出現(xiàn)在當(dāng)用戶手動輸入結(jié)構(gòu)化SQL時,例如,設(shè)想寫一個方法來從一個聯(lián)系搜索頁面收集聯(lián)系信息列表,為了
防止在你的系統(tǒng)里讀取每個單獨的郵件時遇到垃圾郵件,我們將強迫用戶在我們提供他們的email地址前輸入某人的用戶名:
Java代碼 復(fù)制代碼
  1. def user_contacts(request):   
  2.     user = request.GET['username']   
  3.     sql = "SELECT * FROM user_contacts WHERE username = '%s';" % username   
  4.     # execute the SQL here...  

注意,這個例子中,以及下面所有類似的"不要做這個"的例子中,我們故意保留了大部分用來讓方法真正工作的代碼,我們
不會讓這些代碼在某人偶然取走它們時工作
盡管起初這看起來不危險,但它真的是這樣
首先,保護我們的整個郵件列表的嘗試將以一個聰明的結(jié)構(gòu)化查詢失敗,考慮如果一個攻擊者輸入"' OR 'a'='a"到查詢框里
這種情況下,字符串插補將構(gòu)建的查詢將為:
Java代碼 復(fù)制代碼
  1. SELECT * FROM user_contacts WHERE username = '' OR 'a' = 'a';  

由于我們在該字符串里允許不安全的SQL,攻擊者添加的OR子句確保每個單獨的行都返回
盡管如此,這是最小的引起驚慌的攻擊,設(shè)想一下如果攻擊者提交"'; DELETE FROM user_contacts WHERE 'a' = 'a"將發(fā)生
什么,我們將得到這個完整的查詢:
Java代碼 復(fù)制代碼
  1. SELECT * FROM user_contacts WHERE username = ''; DELETE FROM user_contacts WHERE 'a' = 'a';  

呀!我們的聯(lián)系列表哪里去了?

解決方案
盡管這個問題很陰險并且有時很難發(fā)現(xiàn),解決方案卻很簡單:從不信任用戶提交的數(shù)據(jù),并且當(dāng)傳遞給SQL時一直escape它
Django數(shù)據(jù)庫API為你做這個,它根據(jù)你使用的數(shù)據(jù)庫服務(wù)器(例如PostgreSQL,MySQL)的引號慣例自動escape所有特殊的SQL
參數(shù),例如,在這個API調(diào)用中:
Java代碼 復(fù)制代碼
  1. foo.get_list(bar__exact="' OR 1=1")  

Django將相應(yīng)的escape輸入,結(jié)果是像這樣的語句:
Java代碼 復(fù)制代碼
  1. SELECT * FROM foos WHERE bar = '\' OR 1=1'  

這是完全無害的
這適合所有的Django數(shù)據(jù)庫API,帶有一些額外情況:
1,extra()方法的where參數(shù)(參考附錄XXX),該參數(shù)設(shè)計時接受原始SQL
2,使用低級數(shù)據(jù)庫API來手動進行查詢
對于其中每種情況,很容易讓你自己受保護,每種情況下,避免字符串插補有利于傳遞"綁定參數(shù)",即,這部分我們開始的
例子應(yīng)該被寫成:
Java代碼 復(fù)制代碼
  1. from django.db import connection   
  2.   
  3. def user_contacts(request):   
  4.     user = request.GET['username']   
  5.     sql = "SELECT * FROM user_contacts WHERE username = %s;"  
  6.     cursor = connection.cursor()   
  7.     cursor.execute(sql, [user])   
  8.     # ... do something with the results  

低級execute方法使用SQL字符串和%s placeholders,并且自動escape和插入作為第二個參數(shù)傳遞的列表參數(shù),你應(yīng)該一直以
這種方式構(gòu)建自定義的SQL
不幸的是,你不能在SQL的每個地方使用綁定參數(shù),它們不允許作為標識符(即表名或者列名),這樣,如果你需要,如從一個
POST變量動態(tài)構(gòu)建表的列表,你將需要在你的代碼里escape該名字,Django提供了一個方法django.db.backend.quote_name
它將根據(jù)當(dāng)前數(shù)據(jù)庫的引號scheme來escape標識符

跨站點腳本(XSS)
很可能最常見的web弱點,跨站點腳本,或者XSS,在渲染到HTML之前失敗于正確的escape用戶提交的內(nèi)容的web程序里發(fā)現(xiàn)
這允許攻擊者惡意的插入任意的通常是script標簽格式的HTML
攻擊者通常使用XSS攻擊來竊取cookie和session信息,或者騙取用戶提供私有信息給錯誤的人(也叫phishing)
這種類型的攻擊可以采用一些不同的形式,并且有幾乎無限的改變方式,所以我們將只看看一個典型的例子,讓我們看看一
個非常簡單的"hello world"視圖:
Java代碼 復(fù)制代碼
  1. def say_hello(request):   
  2.     name = request.GET.get('name''world')   
  3.     return render_to_response("hello.html", {"name" : name})  

這個視圖簡單的從GET參數(shù)讀取一個名字并傳遞名字給hello.html模板,我們可能像這樣為該視圖寫一個模板:
Java代碼 復(fù)制代碼
  1. <h1>Hello, {{ name }}!</h1>  

所以如果我們訪問http://example.com/hello/name=Jacob,渲染的頁面將包含:
Java代碼 復(fù)制代碼
  1. <h1>Hello, Jacob!</h1>  

但是等等--如果我們訪問
Java代碼 復(fù)制代碼
  1. http://example.com/hello/name=<i>Jacob</i>  

會發(fā)生什么?
則我們會得到:
Java代碼 復(fù)制代碼
  1. <h1>Hello, <i>Jacob</i>!</h1>  

當(dāng)然,攻擊者不會使用像i標簽的東西,他可以包含整個HTML集來用任意內(nèi)容截取你的頁面,這種類型的攻擊被用來欺騙用戶
輸入數(shù)據(jù)到看起來像它們的銀行網(wǎng)站,但是事實上是把你的帳號信息發(fā)送給攻擊者的XSS-截取表單
如果你把存儲該數(shù)據(jù)在數(shù)據(jù)庫中并且后面在你的站點上顯示則會更糟
例如,在某點上MySpace被發(fā)現(xiàn)對于這種類型的XSS攻擊有弱點,用戶插入javascript到他的當(dāng)你訪問他的profile頁面時自動
添加他為你的朋友的profile里,幾天之內(nèi)他有了幾百萬的朋友
現(xiàn)在,這可能聽起來良好,但是記住該攻擊者讓他的代碼--而不是MySpace的--運行在你的電腦里,這違反了對于信任MySpa
ce上面的所有代碼都是事實上由MySpace所寫的假設(shè)
MySpace非常幸運這些惡意的代碼沒有自動刪除訪問者的帳號,更改他們的密碼,用垃圾郵件淹沒站點,或者其他任何該弱點
釋放的惡夢般的情形
的情形

解決方案
解決方案非常簡單:一直escape任何可能來自于用戶的內(nèi)容,如果我們像這樣簡單的重寫我們的模板:
Java代碼 復(fù)制代碼
  1. <h1>Hello, {{ name|escape }}!</h1>  

則我們不再易受攻擊了,你應(yīng)該當(dāng)在你的站點上顯示用戶提交的內(nèi)容時一直使用escape標簽(或者一個相似物)
為什么Django不為你做這些?
修改Django來自動escape所有顯示在模板中的變量是一個頻繁出現(xiàn)在Django開發(fā)人員郵件列表中的討論主題
目前為止,Django的模板避免了這種行為,因為它敏銳而不可見的更改了應(yīng)該很直接的行為(顯示變量),這是個狡猾的問題
和一個很難評價的平衡,添加隱藏的行為與Django的核心理念相悖(以及Python的,對于這種問題),但是安全同等重要
然而,也存在公平的機會使得Django在未來添加某種形式的自動escape(或者幾乎自動escape)行為,它將一直比本書更新
(特別是最終樹版本)
即使Django添加了這個特性,你應(yīng)該仍然一直保有考慮"該數(shù)據(jù)從哪里來?"的習(xí)慣,沒有一直100%保護你的站點免受XSS攻擊
的自動解決方案

跨站點請求偽造(CSRF)
CSRF當(dāng)惡意網(wǎng)站欺騙用戶未知的從一個他們已經(jīng)認證的站點載入一個URL時發(fā)生--這樣,就可以使用他們的認證狀態(tài)
Django由內(nèi)勁攻擊來防護這種類型的攻擊,攻擊本身和那些工具在第15章進行了詳述

Session偽造/截取
這是一個特殊的攻擊,而不是對用戶的session數(shù)據(jù)的一般類型的攻擊,它可以有一些不同的形式:
1,中間人攻擊,其中攻擊者當(dāng)它在有線(或者無線)網(wǎng)絡(luò)上游走時竊聽session數(shù)據(jù)
2,Session偽造,其中攻擊者使用偽造的session ID(可能通過中間人攻擊獲得)來假裝為另外一個用戶
這前兩種的例子是在咖啡店的攻擊者使用無線網(wǎng)絡(luò)來獲取一個session cookie,然后他可以使用這個cookie來模仿原始用戶
3,cookie偽造攻擊,其中攻擊者覆蓋存儲在cookie中的假定只讀的數(shù)據(jù),第12章詳細解釋了cookies怎樣工作,其中一個突
出點是對瀏覽器和惡意用戶在你不知情的情況下更改cookies是微不足道的
網(wǎng)站存儲類似于IsLoggedIn=1或者甚至LoggedInAsUser=jacob的cookie有很長的歷史,開拓這種類型的攻擊者太容易了
但是對于在更微妙的級別,信任任何存儲在cookie中的東西從不是個好主意,你從不知道誰正在翻找它們
4,Session定置,其中攻擊者欺騙用戶設(shè)置或者重設(shè)他們的session ID
例如,PHP允許session標識符在URL中傳遞(即http://example.com/?PHPSESSID=fa90197ca25f6ab40bb1374c510d7a32),欺騙
用戶點擊一個硬編碼了session ID的鏈接的攻擊者將導(dǎo)致用戶采用該session
這被用在phishing攻擊中來欺騙用戶輸入個人信息到攻擊者所有的帳號,它可以稍后登錄該帳號并得到那些數(shù)據(jù)
5,Session下毒,其中攻擊者注射潛在危險的數(shù)據(jù)到用戶的session中--通常通過一個用戶提交來設(shè)置session數(shù)據(jù)的web表單
一個規(guī)范的例子是站點在cookie中存儲簡單的用戶喜好(例如頁面背景顏色),攻擊者可以欺騙用戶點擊一個連接來提交一個
事實上包含XSS攻擊的"顏色",如果這個顏色沒有escape(參考上面的)用戶可能再次注射惡毒的代碼到用戶環(huán)境

解決方案
有一些可以防止遭受這些攻擊的一般原則:
1,從不允許session信息包含在URL中
Django的session框架(參考第12章)簡單的不允許session包含在URL中
2,不要在cookies中直接存儲數(shù)據(jù),相反,存儲映射到存儲在后端的session數(shù)據(jù)的session ID
如果你使用Django內(nèi)建的session框架(即request.session),它可以自動為你處理,session框架使用的唯一的cookie是一個
單獨的session ID,所有的session數(shù)據(jù)存儲在數(shù)據(jù)庫中
3,如果你在模板中顯示session數(shù)據(jù)記得escape它,參考上面的XSS部分,并且記得它適合任何用戶創(chuàng)建的內(nèi)容,你應(yīng)該把
session信息當(dāng)作用戶創(chuàng)建的
4,預(yù)防任何可能的攻擊者竊取session IDs
盡管幾乎不可能檢測到某人在竊取session ID,Django確實有內(nèi)建的強力的session攻擊的防護,Session IDs存儲為哈希(而
不是連續(xù)的數(shù)字),這防止了強力攻擊,并且如果用戶嘗試一個不存在的sessino ID時用戶將一直得到一個新的session ID,
這防止了session定置
注意這些原則和工具中沒有一個防止了中間人攻擊,這種類型的攻擊幾乎無法檢測,如果你的站點允許登錄用戶看到一些類
型的敏感數(shù)據(jù),你應(yīng)該一直通過HTTPS來服務(wù)站點,而且,如果你有一個允許SSL的站點,你應(yīng)該設(shè)置SESSION_COOKIE_SECURE
設(shè)置為True,這將使Django只通過HTTPS發(fā)送session cookie

E-mail頭部注射
SQL注射的很少有人知道的姐妹e-mail頭部注射竊取email發(fā)送web表單并使用它們來發(fā)送垃圾郵件,任何從web表單數(shù)據(jù)構(gòu)建
email頭部的形式都是這種類型的攻擊
讓我們看看規(guī)范的許多站點的聯(lián)系人表單,通常它email一個硬編碼的email地址,所以第一眼看來沒有垃圾郵件濫用的攻擊
盡管如此,大部分的這種表單也允許用戶輸入他自己的email主題(還有一個發(fā)送地址,有時候一些其他域),這個主題域被
用來構(gòu)建email信息的主題頭部
如果當(dāng)構(gòu)建email信息時頭部沒有escape,攻擊者可以使用類似于"hello\ncc:spamvictim@example.com"(這里\n是換行字符)
這將使得構(gòu)建的email頭部變成:
Java代碼 復(fù)制代碼
  1. To: hardcoded@example.com   
  2. Subject: hello   
  3. cc: spamvictim@example.com  

和SQL注射一樣,如果我們信任用戶給定的主題行,我們將允許他后見一些惡意的頭部,則它們可以使用我們的聯(lián)系表單來
發(fā)送垃圾郵件

解決方案
我們可以用我們預(yù)防SQL注射同樣的方式來防止這種攻擊:一直escape或者驗證用戶提交的內(nèi)容
Django內(nèi)建的mail方法(位于django.core.mail)簡單的不允許用于構(gòu)建頭部(發(fā)送和接受地址以及主題)的任何域中有換行
如果你嘗試使用django.core.mail.send_mail和一個包含換行的主題,Django將觸發(fā)BadHeaderError異常
如果你決定使用發(fā)送email的其他方法,你將需要確認頭部的換行導(dǎo)致出錯或者被清除,你可能想檢查django.core.mail中的
SafeMIMEText類來看看Django怎樣做這件事

目錄穿越
目錄穿越使另一個注射風(fēng)格的攻擊,其中惡意的用戶欺騙文件系統(tǒng)代碼來讀和/或?qū)憌eb服務(wù)器應(yīng)該不允許訪問的文件
一個例子可能為一個從硬盤讀文件而不清除文件名的視圖:
Java代碼 復(fù)制代碼
  1. def dump_file(request):   
  2.     filename = request.GET["filename"]   
  3.     filename = os.path.join(BASE_PATH, filename)   
  4.     content = open(filename).read()   
  5.   
  6.     # ...  

盡管它看起來限制了文件訪問為訪問BASE_PATH(通過使用os.path.join)下面的文件,如果攻擊者傳遞一個包含..(這是兩個
句點,UNIX對"父目錄"的捷徑)的filename,他可以訪問BASE_PATH"之上"的文件,他發(fā)現(xiàn)正確數(shù)量的小數(shù)點來成功訪問只是
時間問題,比如../../../../../etc/passwd
讀取文件而不正確的escape的東西對于此問題是易受攻擊的,寫文件的視圖只是易受攻擊,但結(jié)果加倍可怕
另一個該問題的改變位于基于URL或者其他請求信息動態(tài)載入模塊的代碼中,一個宣揚良好的例子來自于Ruby on Rails世界
在2006中期之前,Rails使用類似于http://example.com/person/poke/1的URLs來直接載入模塊和調(diào)用方法,結(jié)果是細心組織
的URL可能自動載入任何的代碼,包括一個數(shù)據(jù)庫重置腳本!

解決方案
如果你的代碼需要基于用戶輸入讀寫文件,你需要非常小心的清除請求路徑來確保攻擊者不能從你限制訪問的基本目錄逃離
注意,不需要說,你應(yīng)該從不寫可以讀取硬盤任何位置的代碼
怎樣做這個escape的好例子位于Django內(nèi)建的靜態(tài)內(nèi)容服務(wù)視圖(位于django.views.static),這里是相關(guān)的代碼:
Java代碼 復(fù)制代碼
  1. import os   
  2. import posixpath   
  3.   
  4. # ...   
  5.   
  6. path = posixpath.normpath(urllib.unquote(path))   
  7. newpath = ''  
  8. for part in path.split('/'):   
  9.     if not part:   
  10.         # strip empty path components   
  11.         continue  
  12.   
  13.     drive, part = os.path.splitdrive(part)   
  14.     head, part = os.path.split(part)   
  15.     if part in (os.curdir, os.pardir):   
  16.         # strip '.' amd '..' in path   
  17.         continue  
  18.   
  19.     newpath = os.path.join(newpath, part).replace('\\', '/')  

Django本身不讀文件(除非你使用static.serve方法,但是它被上面顯示的代碼保護),所以這個弱點不會影響核心代碼很多
另外,使用URL配置抽象意味著Django將從不載入你沒有顯示告訴它載入的代碼,沒有創(chuàng)建一個URL來導(dǎo)致Django載入沒有在
URL配置里提到的東西的方式

暴露出錯信息
在開發(fā)階段,可以在你的瀏覽器里看到堆棧和出錯信息是非常有用的,Django有特別讓調(diào)試容易的非常"漂亮"和豐富的調(diào)試
信息
盡管如此,一旦站點上線的話如果這些錯誤還顯示,它們有時候會無意的暴露幫助攻擊者的你的代碼或者配置的一些方面
而且,錯誤和堆棧信息對最終用戶根本沒有用處,如果你點代碼觸發(fā)了不可處理的異常,站點訪問者應(yīng)該不能看到完整的
堆棧信息--或者任何代碼片段或者Python(面向程序員的)出錯信息,相反,訪問者應(yīng)該看到友好的"該頁面不可得到"信息
當(dāng)然,自然開發(fā)者需要看到堆棧信息來在他們的代碼中調(diào)試問題,所以框架應(yīng)該從公眾隱藏所有的出錯信息,但是它應(yīng)該
顯示他們給受信任的站點開發(fā)人員

解決方案
Django有一個簡單的標記來控制這些錯誤新的顯示,如果DEBUG設(shè)置被設(shè)為True,錯誤信息將顯示在瀏覽器中,否則Django
將渲染返回一個HTTP500("內(nèi)部服務(wù)器錯誤")信息并渲染一個你提供的錯誤模板,這個錯誤模板被稱作500.html,并且應(yīng)該
位于一個你的模板目錄的根目錄
既然開發(fā)人員仍然需要看到上線站點生成的錯誤信息,對于任何這種方式處理的錯誤將把完整的堆棧信息發(fā)送email給在
ADMINS設(shè)置中給定的任何地址
在Apache和mod_python下部署的用戶應(yīng)該也確認他們在他們的Apache配置文件里設(shè)置了PythonDebug Off,這將確保任何在
Django有機會載入之前發(fā)生的錯誤都將不會顯示給公眾

最后一句話
希望所有這些關(guān)于安全問題的探討不會太有脅迫感,是這樣,web可以是一個瘋狂和野蠻的世界,但是通過一丁點的遠見,你
可以有一個難以置信的安全網(wǎng)站
記住web安全是一個不斷改變的領(lǐng)域,如果你在閱讀本書的最終樹版本,確保檢查更多更新的對于已發(fā)現(xiàn)的新弱點的安全資源
事實上,每個月或者每星期花費一些時間來研究和保持當(dāng)前狀態(tài)的web程序安全一直是個好主意,這是很小的投資,但是你得
 
安徽新華電腦學(xué)校專業(yè)職業(yè)規(guī)劃師為你提供更多幫助【在線咨詢