Brakemanを自作アプリに導入してみた

現在、フィヨルドブートキャンブ内にて、@Sakiさん主催の「パーフェクト Ruby on Rails輪読会」が行われています。 こちらの本、大変参考になりますが、なんだか難しいし、もう少し深掘りがしたい!と思いまして、このブログに予習・復習した内容を簡単に載せていきたいなと考えています。

9-3-2

Brakemanはアプリの脆弱性を静的解析してくれる便利なgem

RailsConfでの発表の動画を見る限り、読み方は「ブレーキマン」ではなく「ブレークマン」っぽい。
使い所はCIで定期実行して、脆弱性につながる疑いのコードを事前に検知するとよいとのこと。
XSSSQLインジェクションなどの脆弱性を確認してくれ、その確認項目は30項目くらいありそう。

Railsで作ったアプリでは警告等が出なかったので、せっかくなので自作アプリのNursePicksに導入してみる。

group :development do
  gem 'brakeman'
end

bundle exec brakemanで実行してみると、レポートが作成された。

== Brakeman Report ==

Application Path: work/nursepicks
Rails Version: 6.1.6
Brakeman Version: 5.3.1
Scan Date: 2022-11-16 17:06:57 +0900
Duration: 1.213567 seconds
Checks Run: BasicAuth, BasicAuthTimingAttack, CSRFTokenForgeryCVE, ContentTag, CookieSerialization, CreateWith, CrossSiteScripting, DefaultRoutes, Deserialize, DetailedExceptions, DigestDoS, DynamicFinders, EOLRails, EOLRuby, EscapeFunction, Evaluation, Execute, FileAccess, FileDisclosure, FilterSkipping, ForgerySetting, HeaderDoS, I18nXSS, JRubyXML, JSONEncoding, JSONEntityEscape, JSONParsing, LinkTo, LinkToHref, MailTo, MassAssignment, MimeTypeDoS, ModelAttrAccessible, ModelAttributes, ModelSerialize, NestedAttributes, NestedAttributesBypass, NumberToCurrency, PageCachingCVE, PermitAttributes, QuoteTableName, Redirect, RegexDoS, Render, RenderDoS, RenderInline, ResponseSplitting, RouteDoS, SQL, SQLCVEs, SSLVerify, SafeBufferManipulation, SanitizeConfigCve, SanitizeMethods, SelectTag, SelectVulnerability, Send, SendFile, SessionManipulation, SessionSettings, SimpleFormat, SingleQuotes, SkipBeforeFilter, SprocketsPathTraversal, StripTags, SymbolDoSCVE, TemplateInjection, TranslateBug, UnsafeReflection, UnsafeReflectionMethods, ValidationRegex, VerbConfusion, WithoutProtection, XMLDoS, YAMLParsing

== Overview ==

Controllers: 11
Models: 6
Templates: 17
Errors: 0
Security Warnings: 4

== Warning Types ==

Cross-Site Scripting: 4
Cross-Site Scripting: 4

== Warnings ==

Confidence: Weak
Category: Cross-Site Scripting
Check: SanitizeConfigCve
Message: rails-html-sanitizer 1.4.2 is vulnerable to cross-site scripting when `select` and `style` tags are allowed (CVE-
2022-32209). Upgrade to 1.4.3 or newer
File: Gemfile.lock
Line: 273

Confidence: Weak
Category: Cross-Site Scripting
Check: LinkToHref
Message: Potentially unsafe model attribute in `link_to` href
Code: link_to(Post.find(params[:post_id]).url, :target => :_blank, :rel => "noopener", :class => "post-image")
File: app/views/posts/show.html.slim
Line: 5

Confidence: Weak
Category: Cross-Site Scripting
Check: LinkToHref
Message: Potentially unsafe model attribute in `link_to` href
Code: link_to(Post.find(params[:post_id]).title, Post.find(params[:post_id]).url, :target => :_blank, :rel => "noopener")
File: app/views/posts/show.html.slim
Line: 9

Confidence: Weak
Category: Cross-Site Scripting
Check: LinkToHref
Message: Potentially unsafe model attribute in `link_to` href
Code: link_to(User.find(params[:id]).url, User.find(params[:id]).url)
File: app/views/users/show.html.slim
Line: 11

何やらCross-Site Scriptingで4件の警告あり。
内訳としては3件がLinkToHref、1件がSanitizeConfigCve
1つ1つの警告の詳細についてはbrakeman/docs/warning_types/

link_toメソッドの指摘に関しては

Brakemanはlink_toメソッドを使って作成されたURLにユーザー入力が含まれていると警告を発します。Railsにはこの方法で作成されたURLを安全にする方法がないため(例:プロトコルをHTTP(S)に限定する、など)、安全なメソッドを無視したい場合は次のオプションを使ってください。 Brakeman: Options

伊藤さんが翻訳してくれている。
ということで今回はurlメソッドで怒られてるので、--url-safe-methods urlとオプションをつけておく。

あとはrails-html-sanitizerをアップグレード。
対象コードを修正すると、

== Overview ==

Controllers: 11
Models: 6
Templates: 17
Errors: 0
Security Warnings: 0

== Warning Types ==


No warnings found

ということで修正完了。

GithubActionsにも設定、CIでも実行できるようにした。

- name: Breakeman
  run: bundle exec brakeman --url-safe-methods url

ちなみにbrakeman -Iコマンドで無視する警告を設定できるとのこと
参考記事:Brakemanで無視する警告の設定の仕方 - Qiita
breakman -Aでデフォルトでは検証しない、すべてのチェックも実行してみたが、Unscoped Findなど偽陽性のものも多いので、この設定をしておけばよさそう。

その他参考記事

セキュリティ対策ができるし、特に自作アプリでは変更のたびに誰かにレビューしてもらうことはないので、こういった静的解析ツールは便利!