おもしろwebサービス開発日記

Ruby や Rails を中心に、web技術について書いています

`config.active_support.hash_digest_class = OpenSSL::Digest::SHA256` とはなんなのか

時折、仕事でRailsのconfig.load_defaultsのバージョンを上げていく作業をしています。具体的には上げるバージョンに含まれるそれぞれの設定の意味を理解して、影響範囲を把握したうえで一つづつPull Requestを作るようにしています。実際にやってみた感想としては、これはなかなか難易度が高くきちんと影響範囲を理解したうえで実施できているプロジェクトは少ないのではないか?と思いました。そこで、これからconfig.load_defaultsのバージョンを上げる人の役に立つようにブログエントリを書いてみた次第です。

今日はconfig.load_defaults 7.0に含まれるconfig.active_support.hash_digest_class = OpenSSL::Digest::SHA256を取り上げます。

config.active_support.hash_digest_class = OpenSSL::Digest::SHA256は、主にキャッシュのキーに対して利用するハッシュ関数をSHA256にする、というものです。もともとのハッシュ関数はMD5でしたが、Rails5.2でデフォルトSHA1に変更され、7.0ではSHA256になりました。

今回のハッシュ化の対象はキャッシュキーであるため、SHA1が脆弱なのが問題というわけではありません。Rails全体としてSHA256を使うようにするとセキュリティ標準を満たしているかどうかのチェックが楽になる、という理由で変更が反映されたようです。

Rails内で関連のある部分

Railsのコードを見る限り、利用している箇所は次の4箇所です。

基本的にこれらのキャッシュを利用していなければ問題なく設定を変更できそうです。

変更が影響する箇所の確認方法

キャッシュを利用しているかどうかは十分なテストカバレッジがあれば、次のようなモンキーパッチで確認できます*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:「長いキャッシュキーを縮める」の箇所を除く