• 让数据说话

    2017

    2023

  • CookieStore 儲存方式 在 多主機 or multi process 的狀態下,運作可以運作的很好

    尤其是需要應付高並發的情境下 ( 如:每年的 1111 / 1212 .. etc ) 除了可減少主機內部網路負擔,也可以避免伺服器之間,可能會有過度依賴的問題

    因為你加開的主機越多,只要有負責處理特定服務的主機掛掉,整體系統就會垮掉無法使用 所以你必須在硬體主機上 或 架構上做一些調整,以便成本可以控制得住,又可以達成相同的目的

    就以 database 跟 存放 session 主機來看,我一定要讓 database 要活著,因為這不能掛 但有關 session 的存放我就可以另尋方案,像 CookieStore 的方式我可能就會考慮

    我個人重新審視使用 CookieStore 時,是因為 Elixir 的 Phoenix Framework ( 狀況需要 ) 仔細研究了一下,他們也是採用加密的 cookie,所以非常容易實現高並發, 若採 redis、memcache 的方案,恐怕速度未必拉得起來,而且可能會有東西先掛掉

    以前 new 一個 rails 的專案都是直接將 cookie store 換掉 ( 過去的習慣 ) 直到平台的架構需要 ( 提升性能 ) 才覺得這個設計好像也沒有什麼問題。

    但我在研究的過程中,有發現一個安全上的缺點

    第一,decrypt 已加密的 cookie 腳本到處找得到 第二,相關的 salt 值意外的很簡陋

    根據 https://edgeguides.rubyonrails.org/configuring.html 的描述 用來為 cookie 做加密的兩組 salt 值 signed_cookie_salt、encrypted_cookie_salt 也似乎不曾在專案的設定裡

    Rails.application.config.action_dispatch.encrypted_cookie_salt
    # 結果為 "encrypted cookie"
    
    Rails.application.config.action_dispatch.encrypted_signed_cookie_salt
    # 結果為 "signed encrypted cookie"
    

    換句話說,只要你的系統專案、平台,開發成員離職 or 退出,若他們仍記著 secret key

    就可透過以下的方式解回 cookie

    # 可在網路搜尋到 Rails 4 ~ 5.x 的 session cookie 解回的方法
    def verify_and_decrypt_session_cookie(cookie, secret_key_base)
      cookie = CGI::unescape(cookie)
      salt = "encrypted cookie"
      signed_salt = 'signed encrypted cookie'
      key_generator = ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000)
      secret = key_generator.generate_key(salt)[0, 32]
      sign_secret = key_generator.generate_key(signed_salt)
      encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON)
    
      encryptor.decrypt_and_verify(cookie)
    end
    

    既然可以解回來,是不是有可能根據 Rails 4、5、6 的版本做出破解,甚至將改過的資料送回 原本的伺服器, 以便偽造資料,我沒有時間可以驗證 但我有印象根據 rails 的 changelog 上,有發現他們有改進 CookieStore 的一些安全上的缺陷

    但無論如何,我認為還是要再更新這兩組 salt,定時更換會比較妥當

    ( 這兩組設定要另外 key 上去,沒有在註解裡的樣子 )

    Rails.application.configure do
    
      # 設定 兩組 salt 給 encrypted cookie,salt 的長度隨意,記得定時偶爾換就好
      config.action_dispatch.encrypted_cookie_salt = '26c8e554....'
      config.action_dispatch.encrypted_signed_cookie_salt = '098d7fdd....'
    
    end
    

    此外,為了讓 session data 無效,更換 secret_key_base 是可能極為冒險的

    如果假設你的系統有套上 devise 作為會員登入系統的基礎

    根據 devise 的文件的描述,原始碼 Devise::SecretKeyFinder 這個 module

    他會抓 secret_key_base 來作為 忘記密碼、註冊認證信的連結使用,

    若你為了 session 無效而更換下去,寄給網友的通知信,裡面的連結都將全數失效,無法使用。

    所以,個人的淺見是,可以更換 encrypted_cookie_salt、encrypted_signed_cookie_salt 來達成目的可能會比較適當。

    不過此部分的更換一定需要在離峰時間處理, 若在平常運作下,系統線上很多人得情況下更換,會產生驚人數量的 invalid csrf token 之類的 exception 記錄在主機上,有掛 New Relic 可能還會收到警報通知不停 QQ

    以上,純屬看法跟經驗分享。

  • 曾因為送修電腦,二個禮拜密集使用 Win10 + WSL 開發 Rails,使用心得是 WSL 相較於現有的解決方案來說,是比較友善且容易處理編譯、安裝相關套件的。但仍會發生權限問題 或 在某些情況下 WSL 掛程式跑會運作到死掉或跳不出程序 ( Ctrl + C ) 😅 😅