devise-securityを使って、よりセキュアなRailsアプリを構築する

# TL;DR
[Devise Security](https://github.com/devise-security/devise-security)を使うことで、過去に使用されたパスワードの制限や多重ログイン禁止などのエンタープライズ向けのセキュアな機能を提供できる。

# はじめに
RailsでWebアプリを作成する際、[Devise](https://github.com/plataformatec/devise)を使って、ユーザ管理を行うことが多いと思います。
Deviseはかなり便利なgemですが、過去に使用されたパスワードの制限や多重ログイン禁止などのエンタープライズ用のセキュリティ要件までは取り扱っていません。
そこで今回はDeviseの使用を前提として、さらに[Devise Security](https://github.com/devise-security/devise-security)を使用して、よりセキュアなRailsアプリを構築します。

# Devise Securityについて
[Devise Security](https://github.com/devise-security/devise-security)は、Deviseの拡張で、下に挙げるような機能を追加します。

ちなみに、開発が止まってしまった[Devise Security Extension](https://github.com/phatworx/devise_security_extension)から**公式に**forkされたもので、Rails 5にも対応するように保守されています。


追加できる機能

- `:password_expirable`：設定された時間が過ぎるとパスワードが自動的に失効します。
- `:secure_validatable`：Devise本家の`:validatable`よりも、さらに強いEmail、パスワード検証をします。（本家の検証がそもそもそこまで強くないのですが...）
- `:password_archivable`：過去に使われたパスワードを`old_passwords`テーブルに格納し、履歴確認をします。
- `:session_limitable`：いちアカウントが一度に1つのセッションしか使えないことを保証します。（つまり、多重ログインの禁止です。）
- `:expirable`：アクティブでない状態がXX日間続いたユーザアカウントを失効します。
- `:security_questionable`：秘密の質問機能を可能にします。
    - **captcha support**：さらに追加的な機能として、`sign_up`、`sign_in`、`recover`、`unlock`に対してcaptchaを導入することができます。 
- `:paranoid_verification`：ユーザがアプリを使うための識別コードを管理者が発行できます。

# 使い方
##### 必要条件
- Rails 4.1以上
- Devise

### インストール
まず、Gemfileに`devise-security`を追加して`$ bundle install`します。

```:Gemfile
gem 'devise-security'
```

### Config設定
次にジェネレータを実行します。
` $ rails generate devise_security:install`

ジェネレータを実行すると、`config/initializers/devise-security.rb`に設定ファイルが作成されるので、それを適宜欲しい機能に応じて修正します。

##### Configuration
```ruby:config/initializers/devise-security.rb
Devise.setup do |config|

  # パスワード有効期限（例. ３ヶ月）
  # config.expire_password_after = 3.months

  # パスワードは英文字（大文字・小文字）と数字、記号を最低1字ずつ含む
  # config.password_complexity = { digit: 1, lower: 1, symbol: 1, upper: 1 }

  # アーカイブする旧パスワードの数
  # config.password_archiving_count = 5

  # 古いパスワードを拒否する？(true, false, count)
  # config.deny_old_passwords = true

  # recoverフォームにcaptchaを導入する？
  # config.captcha_for_recover = true

  # sign upフォームにcaptchaを導入する？
  # config.captcha_for_sign_up = true

  # sign inフォームにcaptchaを導入する？
  # config.captcha_for_sign_in = true

  # unlockフォームにcaptchaを導入する？
  # config.captcha_for_unlock = true

  # recoverフォームに秘密の質問を導入する？
  # captcha_for_recoverが自動的にtrueになります。
  # config.security_question_for_recover = false

  # unlockフォームに秘密の質問を導入する？
  # captcha_for_unlockが自動的にtrueになります。
  # config.security_question_for_unlock = false

  # confirmationフォームに秘密の質問を導入する？
  # captcha_for_confirmationが自動的にtrueになります。
  # config.security_question_for_confirmation = false

  # ==> Configuration for :expirable
  # 最後のアクティブから失効になるまでの時間
  # config.expire_after = 90.days
end
```

### DBスキーマの修正
各機能に応じてDBスキーマを修正します。
詳細は[Devise Security](https://github.com/devise-security/devise-security)のREADMEを見てください。

#### Session limitableの例

```ruby
def change
    add_column :resources, :unique_session_id, :string, limit: 20
end
```

### リソースに機能を付与
Deviseリソースに使う機能を付与します。

#### Session limitableの例
```ruby
devise :database_authenticatable, ..., :session_limitable
```

これでDevise Securityの導入は完了です。

# おわりに
既にDeviseを使っているプロジェクトでは、[Devise Security](https://github.com/devise-security/devise-security)を使うことで容易にエンタープライズ向けのセキュアな機能を提供することができると思います。なかなか有用なgemですが、意外と知られていない気がしたので紹介してみました。