這是我六月初在新加坡 Reddot Ruby Conf 給的演講。原稿投影片放在 Github 上。這篇文章是我自己整理的 Note。
其他的演講多半是重談 OWASP 那些標準需要注意的地方。這個演講當時在設計時,刻意跟其他演講不太同調。原始設計的出發點著重於:如果是一個熟 Rails 架構的 Hacker
(1) 會如何進攻你的 Application
(2) 初學者會在架構設計上犯哪些錯?
(3) 如果你是 Application 設計者,如何一開始就設計出相對安全的架構
在談 Security 之前,我們要來談談 Rails 是不是個「安全」的框架?
平心而論,Rails 的預設是比許多框架要「安全」許多的,它的設計預設就防了很多攻擊手段、屏蔽了開發者設計上的盲點,或者是預設就內置許多最佳實務。
- Helper / View 預設提供了 HTML Escape : 防止 XSS
- ORM 預設提供了 SQL Escape : 防止 SQL Injection
- 表單提供 Authenticity Token :防止 CSRF
- 在 Production mode 錯誤時直接扔 500 頁面:防止 PHP 忘記關 debug mode 結果吐程式碼這種慘劇...
- 熱門的使用者驗證 Gem 如 Devise 直接內置密碼 Bcrypt 加密 :有些開發者懶得自己寫加密 function 乾脆明碼 password 直上
- Sensitive data filtered from log:Rails 的 Log 自動會濾掉一些關鍵字如 [password],以免幹到 Log 就超精彩..
- 熱門的上傳 Gem 如 Paperclip 內建 Filename Sanitization 的實作:防止 path attack
很多傳統打 PHP 網站的方式,是很難拿來直接打 Rails 的,因為一些常見的路都預設被堵死了....
但。這就表示 Rails 不好打嗎?
這也未必。Rails 是個「Framework」。所以其實也有「Pattern」可以依循。一般要打下一個站,去找 Framework 0day 效率通常太低了。找常見的「人為錯誤」其實是比較快的方式...
1. Massive Assignment
Rails 在表單設計上提供了強大的 Helper,表單的 attribute 直接對應到資料庫的欄位。
會生成
看出規律了嗎?所以如果是這樣,從 Chrome DOM Inspect 塞...
通常就可以達到目的...
因為大部分的 Rails Developer 都會寫出這樣的程式碼:
注意 @topic.update_attributes(params[:topic])
那一段。
也有風險的地方:role_ids
除了單一 attribute 會被攻擊外,另外還有一個虛擬的 attribute 設計會有風險。
在這個 user model 裡,使用者擁有很多角色。
Rails 提供一個十分方便的設計。user 可以會自動擁有一個虛擬的 attribute role_id
可以用。role_id
是 Getter 也是 Setter。
如果你在系統的 rails console 下這樣的指令
Rails 會自動幫這個 user 設上 Role id = 1, 2, 3 的三個角色。之所以會有這個「貼心」設計,是因為「大家」都用 checkbox 作多選角色,所以內建了這個設計方便一次設定上多個角色。範例 code 如下:
但這也就表示,其實你的 application 有可能被這樣的假 DOM 玩到的風險....
特別是大家都曉得 role_id = 1
通常就是 admin
。
需要被檢查的地方:
-
has_many
,has_many :through
involve OWNERSHIP, Permission -
user_roles
,group_users
, …. -
UPDATE
action
幾個可能有效的解法:
Rails 3 可以用的解法
( 這個方法在 Rails4 裡被移除了)
- 使用 whitelist attribute
- 打開
config.active_record.whitelist_attributes = true
- 在 model 裡設定
attr_protected :roles
推薦的作法,同時也是 Rails 4 解法
- 使用 Strong parameters。( Rails 4 如果沒過 permit 會直接丟 exception,算直接根除)
params.require(:topic).permit(:title, :body)
進階做法
使用 Reform。出發點是 validation 的責任不應該在 Model 身上,也不該丟給 Controller 去解決,這件事應該要在 Form 層面被解決掉。Reform 的作者同時也是 Cells 的作者 apotonick。
2. Admin
第二部分要談的是 Admin 的設計。這部分也是很讓人無言的。根據非官方統計,高達...99% 的開發者會把 admin 後台放在 ... /admin
...XD
這樣的設計有幾個 concern :
- 容易被猜到放哪裡
- 容易被 XSS 打到
通常建議的解法
把 admin 拆到其他地方去,如 subdomin,或者是不同 domain。
一些其他的基本解法
- 拆到 Intranet 上。(Ineternet 上基本找不到)
-
WiteList.contains?(request.remote_ip)
只准白名單 - 拆到另外一個 Admin App 去管
也有風險的地方:admin?
這也是另外一個有風險的部份。關於 admin?
的實作。多數的開發者,是這樣做的:
然後,就被針對 massive assignment 的攻擊打下來了...
一些解法
-
Setting.admin_emails.include?(email)
// 起碼沒有那麼直觀 - 使用第三方驗證 gem : 如 Github 的 team warden-github-rails 作驗證。想法是:Github 比你家難打太多了....XD 而且其實會是 Admin 的人通常也是 Github 這個 repo 的參加者,用這種方式去驗證比較方便...