時折、仕事でRailsのconfig.load_defaults
のバージョンを上げていく作業をしています。具体的には上げるバージョンに含まれるそれぞれの設定の意味を理解して、影響範囲を把握したうえで一つづつPull Requestを作るようにしています。実際にやってみた感想としては、これはなかなか難易度が高くきちんと影響範囲を理解したうえで実施できているプロジェクトは少ないのではないか?と思いました。そこで、これからconfig.load_defaults
のバージョンを上げる人の役に立つようにブログエントリを書いてみた次第です。
今日はconfig.load_defaults 7.0
に含まれるconfig.active_support.hash_digest_class = OpenSSL::Digest::SHA256
を取り上げます。
- 対象となるコミット: Change the default digest for new apps to SHA256 · rails/rails@ba9207f
- 関連URL: Upgrading Ruby on Rails — Ruby on Rails Guides
config.active_support.hash_digest_class = OpenSSL::Digest::SHA256
は、主にキャッシュのキーに対して利用するハッシュ関数をSHA256にする、というものです。もともとのハッシュ関数はMD5でしたが、Rails5.2でデフォルトSHA1に変更され、7.0ではSHA256になりました。
今回のハッシュ化の対象はキャッシュキーであるため、SHA1が脆弱なのが問題というわけではありません。Rails全体としてSHA256を使うようにするとセキュリティ標準を満たしているかどうかのチェックが楽になる、という理由で変更が反映されたようです。
Rails内で関連のある部分
Railsのコードを見る限り、利用している箇所は次の4箇所です。
- フラグメントキャッシュのキーを決める箇所(テンプレート部分)
- cache メソッド のtemplate tree digestを算出するために使われている
- フラグメントキャッシュの引数で
cache(User.all) do
のようにActiveRecord::Relationを使ったときのキーを決める箇所(id部分)- cache メソッド のidの部分を算出するために使われている
- 強いETagの生成
- 長いキャッシュキーを縮める
基本的にこれらのキャッシュを利用していなければ問題なく設定を変更できそうです。
変更が影響する箇所の確認方法
キャッシュを利用しているかどうかは十分なテストカバレッジがあれば、次のようなモンキーパッチで確認できます*1。下記のコードでは、ActiveSupport::Digest.hexdigest
を実行した場所をログに出力しています。もしCIで並列実行をしているようであれば、適宜ログをマージして確認してください。
# config/application.rb or config/initializers/something.rb module MonkeyPatch def monkeypatch_logger @monkeypatch_logger ||= Logger.new(Rails.root.join('log/monkeypatch.log')) end def hexdigest(*) monkeypatch_logger.debug("ActiveSupport::Digest.hexdigest is called from: #{caller(2, 1).first}") super end end class ActiveSupport::Digest class << self prepend MonkeyPatch end end
テスト実行前に、次のようにキャッシュを有効かつキャッシュストアをNullStoreに設定しておくのを忘れないようにしましょう。
# config/environments/test.rb config.action_controller.perform_caching = true config.cache_store = :null_store
もし利用している箇所があったら、設定変更によりデプロイ後に関連するキャッシュがすべてinvalidになります。負荷が上がることが予想されるので、一時的にアプリケーションサーバやDBサーバを増強する必要がありそうです。
*1:「長いキャッシュキーを縮める」の箇所を除く