play框架的安全設計只是存在於腦海中的一個概念——這就不可能阻止開發者在設計上出漏洞。本指南描述了在Web應用中常見的安全問題,並指導如何在play應用開發中去避免。
一般情況下,你需要保存用戶登錄信息。如果不使用session,用戶就需要在每次請求時傳遞證書。
這就是session要做的事:一系列cookies存儲在用戶的瀏覽器裏,以用於標識不同的站點,並提供其他數據層之外的信息,比如語言。
守住你的安全…安全
session是一個key/values哈希表,有簽名但沒有加密。也就是說主要你的secret是安全的,那麼第三方就不可能僞造session。
而secret存儲在conf/application.conf裏。保持這個文件的私有化非常重要:不要把它提交給公共倉庫,爲防止在安裝某些人寫的應用程序時對secret key進行修改,你可以運行命令play secret進行保護。
不要存儲關鍵性的數據
然後,既然session沒有加密,那麼就不應該在session裏存儲關鍵性安全數據,通過本地網絡連接或wifi連接進行嗅探,它將被看成是用戶的cookie。
session被存儲在cookie裏, 而cookies被限制爲4 KB大小。而且只能存儲String。
跨站點腳本攻擊
在web應用程序中,Cross-site scripting跨站點腳本是最常見的弱點。它包含了利用應用程序提供的窗體惡意注入到web頁面的腳本代碼。
假定這裏有一個博客程序,任何人都可以發表評論,如果評論內容裏包含了攻擊腳本,那麼你將打開你的站點進行攻擊,可能步驟爲:
- 爲訪問者彈出一個窗體
- 跳轉訪問者到被攻擊者控制的站點
- 竊取當前用戶的可見信息,併發回攻擊者的站點
因此爲防止類似攻擊,進行保護非常重要。
play的模板引擎會自動轉義字符串。如果需要在模板裏插入未轉義的HTML代碼,那就需要使用java字符串擴展的 raw() 方法。但如果這個字符串是用戶輸入的,那麼你就需要首先確定它是否是無害的。
在對用戶輸入進行sanitizing消毒的時候,只允許白名單(只允許列表中的安全標籤通過)通過,黑名單(禁止一些不安全的標籤列表)則禁止。
SQL注入
SQL注入所謂SQL注入,就是通過把SQL命令插入到Web表單遞交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令,比如先前的很多影視網站泄露VIP會員密碼大多就是通過WEB表單遞交查詢字符暴出的,這類表單特別容易受到SQL注入式攻擊。這個漏洞可以摧毀數據,或訪問不應該讓當前用戶看到的數據。
當使用高級的“find”方法時,就應該小心sql注入。當手工構建自己的查詢時,儘量不要用+來作連接符,而是用?佔位符。
比如:
createQuery("SELECT * from Stuff WHERE type=?1").setParameter(1, theType);
下面這個就不好了:
createQuery("SELECT * from Stuff WHERE type=" +theType;
跨站點請求僞造CSRF攻擊在web應用程序裏非常危險:
這個攻擊方法通過在用戶信任的web應用程序的頁面里加入惡意代碼或鏈接進行攻擊。如果web應用程序的session沒有設置超時,那麼攻擊者就可以執行未經驗證的命令。
爲預防這類攻擊,首先就是要正確全用GET和POST方法。意思是僅允許POST方法用於修改應用程序的狀態。
對POST請求來說,只有真實的token纔會觸發動作。Play現在內建了一個幫助類用於處理這樣的問題:
- checkAuthenticity() 檢查真實性方法在控制器裏可直接使用,用於檢查請求參數裏的token的真實有效,如果存在問題,就發送一個禁止response的命令。
- session.getAuthenticityToken()方法用於爲當前session生成一個真實可信的token
- #{authenticityToken /}用於創建一個隱藏的輸入域,可用於任何窗體
示例:
public static destroyMyAccount() {
checkAuthenticity();
…
}
上面的方法僅當窗體包含了真實有效的token時,纔會被調用:
<form method="post" action="/account/destroy">
#{authenticityToken /}
<inputtype="submit" value="destroy my account">
</form>
對POST請求來說,Play提供form標籤會自動生成一個有效的token:
#{form @destroyMyAccount()}
<inputtype="submit" value="destroy my account">
#{/form}
如果你想保護所有控制器的action動作,你也可以使用checkAuthenticity()方法作爲before filter進行聽說。
更多跨站點請求僞造見:More on cross-site request forgery。