背景
userの情報を返すAPIを実装する際、render json: user
とするとuserモデルのすべてのフィールドを含むJSONを返してしまい危険です。パスワードはハッシュ化されているものの、deviseが提供するフィールドlast_sign_in_ip
などクライアントに返してはならない個人情報が含まれており、情報漏えいにつながってしまうためです。こちらの記事 も参考にしてください。
上述のような危険な実装をコードレビューのみに頼らずに、Rubyの静的コード解析ツールであるRuboCopで機械的にチェックする方法を、当ページでは記載します。
手順
基本的には公式ドキュメント の手順通りです。
rubocop gemはインストール済みの前提で記載します。
チェック対象のコード
以下の4行目をエラーとすることを目標にします。
コピー # some_controller.rb
class SomeController < ApplicationController
def some_method
user = User . first
render json: user , status: 200 # これを検知したい。statusパラメータは省略可能
end
end
ASTの出力
rubocop gemを入れていれば使えるruby-parse
というコマンドでASTを出力します。
コピー $ ruby-parse some_controller.rb
( class
( const nil :SomeController )
( const nil :ApplicationController )
( def :some_method
( args )
( begin
( lvasgn :user
( send
( const nil :User ) :first ))
( send nil :render
( kwargs
( pair
( sym :json )
( lvar :user ))
( pair
( sym :status )
( int 200 )))))))
検知したいのは、この
コピー (send nil :render
(kwargs
(pair
(sym :json)
(lvar :user))
(pair
(sym :status)
(int 200 ))))))
の部分です。また、renderメソッドの第二引数のstatusは省略可能な引数ですので、第二引数の有無にかかわらず検知できるようにしたいです。
カスタムルールの作成
上記パターンにマッチするようにマッチャを記述します。_や...はワイルドカードです。詳細はドキュメント をご確認ください。
その引数にはjsonという名前付き引数を指定しており
というマッチャを記述しlib/custom_cops/dangerous_render_json.rb
として配置します。
コピー module CustomCops
class DangerousRenderJson < RuboCop::Cop::Cop
# キーワード引数jsonを第一引数にしているrenderメソッド
def_node_matcher :render_json_call? , <<~PATTERN
(send ... :render
(hash
(:pair
(:sym :json)
(_ ...)
)
...
)
)
PATTERN
MSG = 'Do not use render json.'
def on_send ( node )
return unless node . method_name == :render
add_offense(node) if tojson_call?(node)
end
end
end
次に、.rubocop.yml
にて、今作ったカスタムルールを読み込む設定を追記します。
コピー require :
- rubocop-rails
- rubocop-rspec
- ./lib/custom_cops/dangerous_render_json
動作確認
rubocopコマンドを実行して動作確認をします。
うまくいけば、以下のように、エラーとして検知できます。
コピー % bundle exec rubocop
・・・中略・・・
app/controllers/some_controller.rb:4:5: C: CustomCops/DangerousRenderJson: Do not use render json.
render json: user, status: 200 # これを検知したい。statusパラメータは省略可能
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
本サイトの更新情報は、X(旧Twitter)の株式会社プレセナ・ストラテジック・パートナーズエンジニア公式 で発信しています。ご確認ください。