ritouです。
OAuth👮♂️のパトロールによく引っかかる投稿としてこんな感じのがあります。
- Rails で Twitter や facebook とかのアカウントを使ったSNSログイン/ソーシャルログインを実装します!
- devise や omniauth を使います!
- DBのマイグレーション、エンドポイント追加、コールバックの処理、こうして、こう!こうして、こう!
- 動いた!!!
みたいな記事です。
"devise omniauth" で検索するともりもり出てきます。
似たような記事もあるので、誰かが誰かの記事を参考にして書いてそれをまた誰かが...と言うもはや伝統芸能の類のようにも見えてきますが、これ系の記事で気になる点をいくつか残しておきますので今後書く人は参考にでもなさってください。
SNSアカウントから内部のユーザーを引く時のキー
大体の記事は大丈夫ですが、ごく稀にSNSアカウントから取得したメールアドレスをキーにして内部のアカウントを参照している記事が見られます。
このような実装では、Facebook, GithubなどのSNS上でユーザーが登録しているメアドを変更した場合、元のメアドに紐づいているユーザーとしてログイン不可となるでしょう。
また、将来的にメアドがリサイクルされ第3者が利用するようになった場合にも、想定していないアカウント紐付けが発生する可能性があります。
SNSから受け取るメールアドレスは普遍的な値ではない、つまり変更される可能性があるものとして取り扱うべきです。
SNSから受け取ったユーザーIDをキーにしましょう。複数のSNSをサポートする場合はSNSの識別子とユーザーIDとなるでしょう。
このコメントでちょっと細かく書いてます。
https://qiita.com/u-dai/items/91df3b923dc82fed5b76#comment-becfe55135f1aa83064a
英語ですが、Deviseのwikiにも書いてあります。
https://github.com/heartcombo/devise/wiki/OmniAuth:-Overview
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
SNSアカウントに紐づいた User オブジェクトのメアドやパスワード
SNSでログインしようとしたがまだ登録されていない!って言う時に何かちょっと足したりしつつusersテーブルに突っ込むわけです。ここでusersテーブルってののemailとpasswordが必須!でもメアドはSNSアカウントにない場合もあるしパスワードがないのがSNSログインです。
何が行われるかと言うと、メアドならダミーメールアドレスとか言ってSNSのIDとサービス名とかくっつけたりしたダミーメアドを作成したり、パスワードは Devise.friendly_token
とか使ったり。そしてダミーメアドはユーザーに見せない様にしたりします。
この様な方法でSNSでのログインだけを実装する場合は大きな問題とはならないかと思います。サービスからメール送信みたいな機能がなければ。
しかし、すでにメアド/パスワードによるログインを実装済みの所にSNSでのログインを導入!ってやる場合は "ユーザーには見せていない内部用のメールアドレスと、ユーザーには見せていないのでわからないはずのパスワードでログインできる状態" となります。SNSから登録したユーザーのパスワード認証を無効にする方法もありそうですが、そもそもそれができる人はダミーのメアドやランダム風なパスワードなんて生成して保存しないでしょう。
自分が採用したい認証方式を振り返り、パスワード認証を利用している場合はこれが許容できるのかどうか、よく確認する必要があるでしょう。
上述のDeviseのWikiの文章ではこのfriendly_token使ってました。良くないですね。
:provider_ignores_state => true
OAuth 2.0 ベースのSNSの場合、何かのエラーをこのパラメータを設定して乗り越える記事があります。
CSRF対策を行なおうとしたら不足しているロジックがあったためエラーになったものを、CSRF対策自体を取り除くことで回避しようとするのはもはや悪手と言えるでしょう。
終わり
自分は普段Rails使わないので見逃してるものもあるかもしれませんが、せっかくのアウトプットなので他の人のやり方を参考にしつつも悪い実装は避け、全体の質を上げていけると良いと思います。