Precena Tech Book
コーポレートサイト採用サイト
  • はじめに
  • ソフトウェア開発
    • 開発環境構築
      • Homebrew
        • Homebrew用語の意味
      • ngrok
        • ngrokの導入
        • ngrokのアップグレード(v2 to v3)
      • Slack
        • Slackの/remind コマンドの形式
        • 対面での相談を気軽にするためのSlack設定
      • AWS CLI
      • Ruby
      • Scala
      • Prettier
      • zsh
        • zsh-completion
      • Mac
        • M1 Macでの開発環境構築(rosetta 無し)
    • バックエンド
      • OpenAPI
        • OpenAPI 定義ファイル分割のすゝめ
      • Ruby on Rails
        • ActiveRecordのfind_or_initialize_byメソッドにブロックを渡したときの挙動
        • Railsのアプリケーションサーバーのプロセス数とスレッド数の設定方法
        • Railsを6.1系から7.0系へアップグレードした時に調査したこと
        • schema.rbで差分が発生する事例とその復旧について
        • tmux + overmind を利用して、複数システムを1コマンドで起動できるよう設定する
        • Rails Migrationチートシート
        • GithubのプライベートリポジトリをGemfileで参照する方法
        • ActiveSupportのto_jsonメソッドの注意点
        • 危険なJSON出力を禁止するRuboCopカスタムルールの作成方法
      • Scala
        • Validated を直列に処理したい
      • DB
        • PostgreSQLにおける、削除行に対するロック獲得時の挙動
    • フロントエンド
      • React
        • Storybookを利用したビジュアルリグレッションテスト
  • インフラ開発
    • AWS
      • IAM
        • スイッチロールの設定手順
        • AWS CLIでのスイッチロールの設定手順
        • AWS Vaultを使ったスイッチロール設定手順
        • Github ActionsでIAMロールを利用してAWSリソースを操作する
      • ECS
      • SES
        • AWS SESメールボックスシミュレーターにて、カスタムヘッダや添付ファイル付きのテストEメールを送信する
      • CloudWatch
        • Amazon SNS + Slack Workflowを使って、CloudWatch Alarmの通知をSlackチャンネルへ投稿する
      • Lambda
        • lambrollでAWS Lambda関数をデプロイしたときのTips
    • Heroku
      • HerokuのStackの設定
      • Heroku Postgresの運用でよく使うコマンド集
  • セキュリティ
    • Web
      • Same Origin PolicyとCORS
      • 脆弱性診断 2社同時依頼実施記録
  • Mail
    • SPF、DKIM、DMARCを使用した迷惑メール対策
  • データ分析
    • データ分析プロセス
  • SaaS
    • Zendesk
      • 問い合わせフォームの項目をサービスごとに出し分け、各サービス担当者に自動で振り分けてメールで通知する
  • イベント
    • RubyKaigi
      • RubyKaigi 2023 に現地参加しました
    • EMConf
      • EMConfJP2025_参加レポート
  • やってみた
    • IoT
      • Raspberry Pi + PaSoRi + Python で、勤怠打刻マシンを作ってみた
  • Precena Tech Book 管理
    • コンテンツ執筆時のルール
  • 関連リンク
    • プレセナエンジニア公式Twitter
GitBook提供
このページ内
  • 背景
  • 手順
  • チェック対象のコード
  • ASTの出力
  • カスタムルールの作成
  • 動作確認

役に立ちましたか?

PDFとしてエクスポート
  1. ソフトウェア開発
  2. バックエンド
  3. Ruby on Rails

危険なJSON出力を禁止するRuboCopカスタムルールの作成方法

前へActiveSupportのto_jsonメソッドの注意点次へScala

最終更新 1 年前

役に立ちましたか?

背景

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は省略可能な引数ですので、第二引数の有無にかかわらず検知できるようにしたいです。

カスタムルールの作成

  • renderメソッドを呼び出していて

  • その引数には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)の株式会社プレセナ・ストラテジック・パートナーズエンジニア公式