10.12. CORS 與 CSRF¶
CORS 與 CSRF 是一台對外開放網際網路的相機,在 HTTPS 與登入之外還需要的兩項瀏覽器端防護。各自只需幾行就能設定完成。以下各節會定義該術語,並展示 microdot 的整合方式。
10.12.1. CORS 的作用¶
跨來源資源共用(Cross-Origin Resource Sharing,CORS)是一種瀏覽器機制,讓伺服器得以選擇性地允許特定的其他來源讀取其回應。瀏覽器預設的 同源政策(same-origin policy)會封鎖該讀取:https://example.com 上的 JavaScript 無法讀取來自 https://yard-cam.example.com 的回應,因為不同的主機算作不同的來源。CORS 是伺服器端為選定對等方授予例外的方式。
如果儀表板是由相機本身提供的,那麼每個請求都是同源的,CORS 也就不會起任何作用。當儀表板位於別處時,這套設定才有意義——例如一個公開 URL https://app.example.com,它與位於 https://yard-cam.example.com 的相機通訊:
from microdot.cors import CORS
cors = CORS(
app,
allowed_origins=['https://app.example.com'],
allow_credentials=True,
max_age=86400,
)
allowed_origins 是獲准讀取相機回應的來源清單。是儀表板的來源、而且 只有 儀表板的來源——不是 *——這樣第三方網站才不會意外讀取到相機的回應。
allow_credentials=True 讓跨來源請求得以夾帶 session cookie,這正是儀表板跨越來源邊界保持登入狀態所需要的。
max_age=86400 告訴瀏覽器它可以將預檢(preflight)結果快取一天。瀏覽器在任何使用 GET/HEAD/POST 以外方法、或送出自訂標頭的跨來源呼叫之前,都會額外發出一個 OPTIONS 請求;max_age 將這份額外開銷縮減為每個路由每天一次預檢。
10.12.2. CSRF 的作用¶
跨站請求偽造(Cross-Site Request Forgery,CSRF)是一種攻擊,惡意頁面藉此讓使用者的瀏覽器向一個受信任的伺服器發出一個已通過驗證的請求。即使 CORS 已就位,evil.com 上一個會 POST 到 https://yard-cam.example.com/config 的隱藏 <form> 仍會抵達相機,而瀏覽器會附上相機的 session cookie——cookie 跟隨的是目的地主機,而非發出請求之頁面的來源——於是相機便會樂得處理這個 POST,彷彿它是擁有者所為。
CSRF 防護會拒絕那些請求。microdot.csrf.CSRF 會加入一個中介軟體,它會檢查每個會改變狀態之請求的 Sec-Fetch-Site 標頭,並拒絕任何未標記為 same-origin(或來自 CORS 所允許之來源)的請求:
from microdot.csrf import CSRF
CSRF(app, cors=cors)
傳入 cors 實例可讓中介軟體將儀表板的允許來源納入既有名單(grandfather in)——即使儀表板的 POST 是跨來源的,相機仍然會接受它們。
Sec-Fetch-Site 由現代瀏覽器自動設定;相機在用戶端不必做任何事。對於不送出該標頭的較舊瀏覽器,CORS 允許清單便是後備的檢查機制。
10.12.3. 豁免 webhook¶
如果相機需要一個 webhook 端點來接受來自第三方雲端服務的 POST——例如封存服務供應商的回呼——請將該路由標記為 @csrf.exempt,讓中介軟體放行它。處理常式則必須負責以其他方式驗證該請求——通常是針對承載內容的 雜湊式訊息驗證碼(Hash-based Message Authentication Code,HMAC),以相機與第三方共享的某個祕密計算而成,藉此證明該請求來自知道該祕密的人。後院相機並沒有那些東西,但當你需要時這個裝飾器就在那裡。
10.12.4. 四行的基準設定¶
一旦 HTTPS 就緒,對於任何面向網際網路的相機部署,推薦的堆疊是:
Session(app, secret_key=SECRET,
cookie_options={'http_only': True, 'secure': True})
login = Login()
cors = CORS(app, allowed_origins=[...], allow_credentials=True)
CSRF(app, cors=cors)
本章稍早談到的 session 與登入、此處的 CORS 與 CSRF,以及前一主題的 HTTPS。這四個部分彼此堆疊,並且不會擋到各路由的路。
相機現在可以安全地面向開放的網際網路了——HTTPS、登入、CSRF、CORS。