Rails6のセキュリティチェック環境を整える

## この記事の目的
Railsでのセキュリティ対策を見える化し
セキュリティの脆弱性があれば検出できる仕組み構築を行いました。
その忘備録と、Railsのセキュリティ対策にお困りの方に少しでも参考になればと思い
本記事を書きました。

## 構築環境
- Rails: 6.0.3.3
- Ruby: 2.6.6

## Gem
- Brakeman
- bundler-audit

## 使用するGemについて

### Brakeman
公式サイト：https://brakemanscanner.org/
![brakeman.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555485/49c02bde-ab52-ef09-954b-e4ef83883c36.jpeg)

SQLインジェクション、XSS、Dos攻撃等のセキュリティ脆弱性を検出できるライブラリです。
解析項目は５０種類以上でGitHub,Twitter等でも使われています。
Railsのコードセキュリティ対策として活用をおすすめします。

#### ・インストール方法

Railsプロジェクトには`bundler`でインストールするのが簡単です。
develop環境下にgemを追加し`bundle`してインストールします。

```
group :development do
  gem 'brakeman'
end
```

グローバルにインストールも簡単にできます。

```
gem install brakeman
```

#### ・実行方法

実行方法も簡単です。

Rails環境下で`brakeman`のコマンドを実行するだけで実行が始まります。
下記のサンプルは私のアプリ開発環境の実行結果から引用しております。
私のアプリはDocker-compose 環境ですので 
`docker-compose exec web bash` の後に実行しています。
実行が始まると下記のようにレポートが出力されます。

``` 
❯ docker-compose exec web bash
root@3dde8034237f:~# brakeman
Loading scanner...
Processing application in /app
Processing gems...
[Notice] Detected Rails 6 application
Processing configuration...
[Notice] Escaping HTML by default
Parsing files...
Processing initializers...
Processing libs...ed
Processing routes...          
Processing templates...       
Processing data flow in templates...
Processing models...          
Processing controllers...     
Processing data flow in controllers...
Indexing call sites...        
Running checks in parallel...
 - CheckBasicAuth
 - CheckBasicAuthTimingAttack
 - CheckCrossSiteScripting
 - CheckContentTag
 - CheckCookieSerialization
 - CheckCreateWith
 - CheckCSRFTokenForgeryCVE
 - CheckDefaultRoutes
 - CheckDeserialize
 - CheckDetailedExceptions
 - CheckDigestDoS
 - CheckDynamicFinders
 - CheckEscapeFunction
 - CheckEvaluation
 - CheckExecute
 - CheckFileAccess
 - CheckFileDisclosure
 - CheckFilterSkipping
 - CheckForgerySetting
 - CheckHeaderDoS
 - CheckI18nXSS
 - CheckJRubyXML
 - CheckJSONEncoding
 - CheckJSONEntityEscape
 - CheckJSONParsing
 - CheckLinkTo
 - CheckLinkToHref
 - CheckMailTo
 - CheckMassAssignment
 - CheckMimeTypeDoS
 - CheckModelAttrAccessible
 - CheckModelAttributes
 - CheckModelSerialize
 - CheckNestedAttributes
 - CheckNestedAttributesBypass
 - CheckNumberToCurrency
 - CheckPageCachingCVE
 - CheckPermitAttributes
 - CheckQuoteTableName
 - CheckRedirect
 - CheckRegexDoS
 - CheckRender
 - CheckRenderDoS
 - CheckRenderInline
 - CheckResponseSplitting
 - CheckRouteDoS
 - CheckSafeBufferManipulation
 - CheckSanitizeMethods
 - CheckSelectTag
 - CheckSelectVulnerability
 - CheckSend
 - CheckSendFile
 - CheckSessionManipulation
 - CheckSessionSettings
 - CheckSimpleFormat
 - CheckSingleQuotes
 - CheckSkipBeforeFilter
 - CheckSprocketsPathTraversal
 - CheckSQL
 - CheckSQLCVEs
 - CheckSSLVerify
 - CheckStripTags
 - CheckSymbolDoSCVE
 - CheckTemplateInjection
 - CheckTranslateBug
 - CheckUnsafeReflection
 - CheckValidationRegex
 - CheckWithoutProtection
 - CheckXMLDoS
 - CheckYAMLParsing
Checks finished, collecting results...
Generating report...

== Brakeman Report ==

Application Path: /app
Rails Version: 6.0.3.3
Brakeman Version: 4.9.1
Scan Date: 2020-09-15 02:51:42 +0000
Duration: 2.0712347 seconds
Checks Run: BasicAuth, BasicAuthTimingAttack, CSRFTokenForgeryCVE, ContentTag, CookieSerialization, CreateWith, CrossSiteScripting, DefaultRoutes, Deserialize, DetailedExceptions, DigestDoS, DynamicFinders, 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, SanitizeMethods, SelectTag, SelectVulnerability, Send, SendFile, SessionManipulation, SessionSettings, SimpleFormat, SingleQuotes, SkipBeforeFilter, SprocketsPathTraversal, StripTags, SymbolDoSCVE, TemplateInjection, TranslateBug, UnsafeReflection, ValidationRegex, WithoutProtection, XMLDoS, YAMLParsing

== Overview ==

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

== Warning Types ==


No warnings found

(END)
```

上記のように長いレポートが出力されます。
最後の`Warning Types`以下の出力メッセージが　
`No warnings found` となっていればOKです。

ちなみに警告が発生した場合は下記のようになります。
（下記は公式サイトのQuickStartからの引用です。）
XSSの警告です。

警告発生時にはその内容を読み取って対応を行っていく必要があります。

・https://brakemanscanner.org/docs/quickstart/

![brakeman_text_report.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555485/bc6ed0d6-baad-7ce8-a737-87f1a6eff377.png)

また、Brakemanでは警告出力レベルを３段階で設定が可能です。
GitHubのREADMEには下記の説明があります。

>High - Either this is a simple warning (boolean value) or user input is very likely being used in unsafe ways.
Medium - This generally indicates an unsafe use of a variable, but the variable may or may not be user input.
Weak - Typically means user input was indirectly used in a potentially unsafe manner.

日本語で訳しますと

- High<br>
単純な警告(ブール値)であるか、ユーザー入力が安全でない方法で使用されている可能性が高いかで<br>対策が必要なレベル
- Medium<br>
一般的に変数の安全でない使用を示していますが、変数はユーザ入力である場合もあれば<br>そうでない場合もあるので内容を確認し対応が必要なレベル
- Weak<br>
一般的には、ユーザーの入力が間接的に安全でない可能性のある方法で使用されたことを意味しており、<br>使用方法や設定を確認した方がいいレベル

上記レベルをw1-w3で設定し出力させる事ができます。
w1は最低レベル、w3は最高レベルです。
例えば w3ですと下記のコマンドとなります。
CIでの設定で入れる場合はw2などがいいのかもしれません。

```
brakeman -w3
```

これでRailsのコードをセキュリティチェックする体勢が整いました。

### Bundler-audit

https://github.com/rubysec/bundler-audit

![bundler-audit-cbf59f68.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555485/5093f09b-6caa-3fb6-41b9-4a5dc5184cd6.png)
*画像はbundlerイメージです。

Gemfile.lockの中の脆弱性を検出するツールです。安全でないGemを検出できます。
Brakemanと組み合わせてのインストールがおすすめです。

#### ・インストール方法

Brakemanと同じくGemfileに追加しbundleします。

```
group :development do
  gem 'bundler-audit'
end
```

#### ・実行方法

下記のコマンドで実行を行います。

```
bundle-audit
```

- 脆弱性が無い場合

```
root@3dde8034237f:~# bundler-audit
No vulnerabilities found
```

- 脆弱性がある場合

下記の例ではactionpackのversion3.2.10に脆弱性がある事が示されています。
また解決方法としてSolution:upgrade to ~> 2.3.15, ~> 3.0.19, ~> 3.1.10, >= 3.2.11
バージョン変更が示されています。
脆弱性が示された場合にはバージョン修正の作業を実行して下さい。

```
Name: actionpack
Version: 3.2.10
Advisory: OSVDB-89026
Criticality: High
URL: http://osvdb.org/show/osvdb/89026
Title: Ruby on Rails params_parser.rb Action Pack Type Casting Parameter Parsing Remote Code Execution
Solution: upgrade to ~> 2.3.15, ~> 3.0.19, ~> 3.1.10, >= 3.2.11
```

またGemfileが更新されるような作業が発生する、発生した場合は下記で実行します。
CIで使用する場合も下記が公式サイトでおすすめされています。
bundler-auditはRubyライブラリに関連するすべてのセキュリティ勧告を
コンパイルするために使用される、ruby-advisory-dbを使用しています。
このコマンドではruby-advisory-dbを更新した上でチェックを行うものです。

```
bundle-audit check --update
```

これでGemの脆弱性をチェックする体勢が整いました。

## あとがき
セキュリティ対策はSQLやXSSの対策からDos攻撃等、非常に多岐に渡るチェックが必要で
さらに、コードのセキュリティ対策だけではなく
使用しているGemの脆弱性を発見しなければ
その脆弱性を使用した攻撃のターゲットとなる可能性があると思います。

今回紹介したライブラリはコードとGem
両方面のセキュリティ対策を実行・見える化する上で有効な手段だと思っております。
Rails開発を行われる方の参考になれば幸いです。

＊追記
今回インフラ側のセキュリティ対策は紹介しておりません。
アプリ全般のセキュリティ対策にはRails側だけではなく
インフラ側（AWSではIAMやVPCの設定、暗号化）などが必要となると考えます。