bokunonikki.net

Railsチュートリアルログインまわりのセキュリティまとめ

Sun Dec 1, 2019
Sun Jul 11, 2021

Railsチュートリアルのログインまわりだけやったので、メモ。

セクションハイジャック

記憶トークンを奪って、特定のユーザーになりすましてログインする攻撃。

cookiesを盗み出す有名な方法は4つ

  1. 管理の甘いネットワークを通過するネットワークパケットからパケットスニッファという特殊なソフトウェアで直接cookieを取り出す
  2. データベースから記憶トークンを取り出す
  3. クロスサイトスクリプティング (XSS)
  4. ユーザーがログインしているパソコンやスマホを直接操作してアクセスを奪い取る

対策

  1. Secure Sockets Layer (SSL) をサイト全体に適用して、ネットワークデータを暗号化で保護し、パケットスニッファから読み取られないようにしています
  2. 記憶トークンをそのままデータベースに保存するのではなく、記憶トークンのハッシュ値を保存するようにします。
  3. Railsによって自動的に対策が行われます。具体的には、ビューのテンプレートで入力した内容をすべて自動的にエスケープします
  4. ログイン中のコンピュータへの物理アクセスによる攻撃については、さすがにシステム側での根本的な防衛手段を講じることは不可能なのですが、二次被害を最小限に留めることは可能です。具体的には、ユーザーが (別端末などで) ログアウトしたときにトークンを必ず変更するようにし、セキュリティ上重要になる可能性のある情報を表示するときはデジタル署名 (digital signature) を行うようにします

永続的セッションの作成

  1. 記憶トークンにはランダムな文字列を生成して用いる。
  2. ブラウザのcookiesにトークンを保存するときには、有効期限を設定する。
  3. トークンはハッシュ値に変換してからデータベースに保存する。
  4. ブラウザのcookiesに保存するユーザーIDは暗号化しておく。
  5. 永続ユーザーIDを含むcookiesを受け取ったら、そのIDでデータベースを検索し、記憶トークンのcookiesがデータベース内のハッシュ値と一致することを確認する。

ユーザーを記憶するには、記憶トークンを作成して、そのトークンをダイジェストに変換したものをデータベースに保存します

1
2
3
| userモデル | 説明   
|:-----:|:-----:|
| remember_digest | トークンに対応する記憶ダイジェスト |

user.remember_tokenメソッドを使ってトークンにアクセス(トークンをデータベースに保存せずに実装する必要があります)

password属性はhas_secure_passwordメソッドで自動的に作成されましたが、remember_tokenは自分で実装する必要があります。これを実装するためにattr_accessorを使って「仮想の」属性を作成します。

attr_accessorとはmigrationでオブジェクトのもつ属性を定義することとほぼ同義書き込みも読み込みもできる。migration で定義した型は静的だが、attr_accessorの型は動的に決まる。

暗号化されたユーザーidの照合

  1. cookies.signed[:user_id]でユーザーIDのcookiesの暗号が解除
  2. bcryptを使ってcookies[:remember_token]がremember_digestと一致することを確認
  3. 渡されたトークンがユーザーの記憶ダイジェストと一致することを確認。コードは以下。
1
BCrypt::Password.new(remember_digest).is_password?(remember_token)

Railsメソッド

has_secure_password

  • セキュアにハッシュ化したパスワードを、データベース内のpassword_digestという属性に保存できるようになる。
  • 2つのペアの仮想的な属性(passwordとpassword_confirmation)が使えるようになる。また、存在性と値が一致するかどうかのバリデーションも追加される 。
  • authenticateメソッドが使えるようになる(引数の文字列がパスワードと一致するとUserオブジェクトを、間違っているとfalseを返すメソッド)。

authenticate

has_secure_passwordが提供するメソッド。引数の文字列がパスワードと一致するとUserオブジェクトを、間違っているとfalseを返すメソッド

See Also