Ruby on Rails

【Ruby on Rails5.2】Railsにおけるセキュリティ対策の紹介

・Strong Parameters
・CSRF対策
・インジェクション対策

エンジニアはセキュリティ対策について日々頭を悩ませています。
フレームワークを使えば一般的なセキュリティ対策は網羅されているはずなのであまり意識することは無いですが、書き方によっては意識せざるを得ない場面も出ると思いますので紹介します。

Strong Parameters(ストロングパラメーター)

名前と書き方の関連性が薄いのでRailsを使っている人でも馴染み無いかもしれませんが、リクエストパラメーターを受け取る際に、想定通りであることをチェックしたり必要なパラメーターのみ取得する部分です。

params.require(:user).permit(:name, :email, :password)

本来、ブラウザから送られてくるパラメーターは絞られているのですが悪意のあるパラメーター属性が送られてきた場合を見越して対応するのがStrong Parametersです。

上記コードを意識して使えばuserモデルで定義されているカラム(name,emai,password)だけ、パラメーターを使うことが出来てそれ以外のパラメーターは弾かれます。

Strong Parametersで使うメソッドはrequireとpermitだけです。
ネストしているパラメーターを使いたい場合はpermit側も対応する必要があります。

一応Railsには意図しない属性を受け取っても登録・更新は行われませんがStrong Parametersの利用を促されるので基本的には必須となります。
無論、取得属性を絞る行為は、追加した項目に反映されない可能性もはらんでいますので項目追加時には注意が必要です。

CSRF(Cross-site Request Forgery)対策

別のWebアプリケーションの脆弱性を利用してユーザーがログインしているサイトに悪意ある操作をするCSRFですが、Railsでは「form_with」などのヘルパーを使う際に自動で対策されています。

対策内容としては同じWebアプリケーションから生じたリクエストであることを、セキュリティトークンを発行・照合して証明します。

意識しないので便利な反面、POSTリクエストのみの対応なのでGETリクエストで行う場合は意識する必要があります。
基本はPOSTリクエストを行うようにすればCSRF対策は問題無いと思われます。

また、Ajaxリクエスト時のPOSTメソッドもCSRF対策はされています。

Railsガイドー6 AjaxのCSRF(Cross-Site Request Forgery)トークン
https://railsguides.jp/working_with_javascript_in_rails.html#ajax%E3%81%AEcsrf%EF%BC%88cross-site-request-forgery%EF%BC%89%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3

各種インジェクション対策

ユーザーが入力する箇所全てに対して悪意あるスクリプトやパラメーターを入力して内部処理で開発者が意図しない動きをさせるインジェクションも対策されています。

XSS(クロスサイトスクリプティング)

ユーザーに表示するコンテンツに悪意のあるスクリプト(Javascriptとか)を仕掛けて実行させる攻撃方法です。

基本的にはHTMLをエスケープする処理がRailsにはありますが、敢えてエスケープさせない(任意のHTMLタグを反映させたい)場合もあります。
そういった場合は使えるHTMLタグを「sanitize」ヘルパーで絞る対策が必要です。

注意していただきたいのは、任意のHTMLタグを除外するのではなく、 任意のHTMLタグだけを許可するということです。
除外だとパターンが無限にあるため対応難しいですが、許可だと一般的なHTMLタグだけを設定すればそれ以外の意識は不要となります。

SQLインジェクション

少し前にもワクチン接種の予約システムでも、SQLインジェクションの可能性が示唆されているぐらいメジャーなインジェクションです。

Railsの場合、基本的にはActiveRecordのwhereメソッドを使わなければ気にする必要はありません。
ただやはり、whereメソッドを使う場合もあります。そのときはハッシュで渡す書き方を意識します。

User.where(name: params[:name])
User.where("name = ?", params[:name])

sendメソッドが引き起こすインジェクション

教材ではRubyコードインジェクションと記載されています。

Rubyにはsendメソッドが存在します。
定義されている別メソッドを文字列で呼び出すことが出来る便利なメソッドです。

条件によって呼び出すメソッドが違う場合などで真価を発揮できる便利なメソッドですが、悪意あるユーザーが例えば「exit」を入力したらアプリケーションが終了します。
そのためsendメソッドの使用は控えるか、ユーザーが入力した値には使わないなど考慮が必要です。

コマンドラインインジェクション

可能性は低いですがアプリケーションからOSコマンドを実行する場合も注意が必要です。
先程のように悪意あるユーザーが「shutdown」コマンドを入力したらサーバーが落ちてしまいます。

対策としては、そもそもユーザーが入力した値を使わないようにするか、使う場合でも任意の文字列しか使えない許可制にするなどの考慮が必要です。

参考記事

Rails ガイドーRails セキュリティガイド
https://railsguides.jp/security.html