ID/パスワード認証だけのログイン画面から脱出する前にざっくり知っておきたいこと&やることの順番
はじめに
メリークリスマス。
NE株式会社でなんか色々やっているtuです。
マネージャしたり情シスしたり開発もちょっとしたりよくわからないポジションをしてます。
今回は色々なサービスで実装されている"ログイン画面"についてちょろっと書こうと思います。
侮ってはいけないログイン画面
サービス開発していると、だんだんと"利用者ごとに情報の出しわけ"をしたくなってきますよね。
それか今の時代は当たり前になっている機能なので、最初から「とりあえずつくるかー」と作り出してしまうかもしれません。
そこで、とりあえずZennやQiitaで検索。ChatGPTさんにも協力してもらい、MySQLでユーザーテーブル作って、IDとパスワードのカラムを用意し、はい完成。
...これでできるかもしれませんが、 今の時代はこれだけだと不十分です。
なんなら後々めちゃくちゃ苦しむ可能性も。
そのためにもまずは全体像を把握し、何からやっていけばいいかを整理してみようと思います。
ID/Passwordだけで十分なんじゃないの?
まず、簡単に作ったとしてもさすがにパスワードの列はハッシュ化などされてるとします。
すみません...ハッシュ化?ってのしてないんですが...
基本的にユーザーのパスワードは開発者であってもわからないようにしましょう。
ユーザーはIDとパスワードを使い回す傾向があります。 もしそこで得たIDと生のパスワードを使って他のサイトにアクセスできちゃったら?
おめでとうございます。不正アクセス禁止法に抵触しました。
そんなことにならないためにも、または自身が聖人だとアピールするためにも「ハッシュ化」しておきましょう。
ハッシュ化というのは
チキン冷めちゃった -(ハッシュ化)-> 469c70c26c68bbdea9e86e4735b2d92b...
のように、ある文字列を16進数のめちゃくちゃな文字に置き換えることをいいます。
また、特徴として
- 結果が固定の桁数
- 同じ文字列をハッシュ化すると毎回同じ結果になる
- ちょっとでも元の文字列を変えると結果がガラッと変わる
- ハッシュ化された結果から元の文字列を戻すのは基本的に無理
などがあります。
そのため変更や改ざんの検知にも使われます。
md5,sha1,sha256などの色々なハッシュ化の"手法"があります(が、md5やsha1は安全じゃないので使わないでください)。
「暗号化」は元に戻せますが、「ハッシュ化」は基本的に元に戻せません。
だとしても、 もう今の時代はそもそもID/Passwordの認証は安全ではありません。
ブルートフォース、辞書攻撃、ショルダーハッキング、クレデンシャルスタッフィング、などなど...
簡単に突破できるセキュリティ対策の部類になってしまいました。
パスワードを定期的に変更する方法も意味ないとされてます。(末尾に数字つけて更新してませんか?)
時にはスピード重視で作ることもビジネスには必要です。
しかしもしこの状態のままサービスが大きくなったら...? 最近はニュースでも色々騒がれますし、容易に怖い想像ができるのではないかと思います。
数ヶ月〜数年経てば、内部品質は質重視で作り込んだものに逆転されるという話[1]もありますし、 DevSecOpsという考えもありますのでログインページを作るならパッと作らず、最初からしっかり作り込みましょう。大事です。
OK、じゃあ何をすればいい?
調べて行くと"OIDC"とか"JWT"とかのキーワード出てきて「なるほど?なんか良さそうだしこれ実装すればええか!」となるかもしれませんが、ちょっと待って。 それをやるにはまだ早いです。 (もしかしたら経営層から「これやってよ」というオーダーがあったのかもしれませんが...)
これらは後々解説しますが、SSO(シングルサインオン)
をするための、ユーザーを識別する仕組みです。
確かに中の仕組みが変わって若干セキュリティレベルは上がるかもしれません。
が、根本の問題はID/Passwordでの認証が突破されやすい、ということ。
1つ1つ順番に対応していきましょう。
より突破されにくい仕組み
イマドキセキュリティの基本の考え方ID/Passwordは安全ではない、と先ほど言いましたが、他の仕組み(例えば指紋認証とか)でも結局は突破されてしまう時は突破されてしまいますし、 ID/Passwordは今後も一部で利用され続けると思います。
なのでまず、セキュリティ強度を高めるには「多層防御」をすることが基本となります。
その名前の通り「あれがダメでもこっちで防げる」という考えです。
なので、WEBのログイン画面においては「弱いID/Passwordを使わない」ではなく「ID/Password
と その他の情報
」で正しいユーザーかどうかを判断します。
これが「2段階認証」というものです。 例えば「ID/Password
+ メールに送ったコード
」など。
また、2段階で使うそれぞれの「要素」は、上の例ではID/Password
とメールに送ったコード
としていますが、
この要素にも種類があり
- 知っている情報(SYK: Something You Know)
- 例: パスワード、秘密の質問、...
- 弱点: 辞書攻撃、覗き込み、推測、...
- 持っているモノ(SYH: Something You Have)
- 例: スマホ、専用機器、...
- 弱点: 盗難など
- 本人の生体情報(SYA: Something You Are)
- 例: 指紋、静脈、...
- 弱点: 指紋コピーなど
現在は上記3種類に分類され、下に行くほど(SYK→SYH→SYAの順で)盗まれにくく、"強い情報"となっています。[2]
上記からより強い要素を2つピックアップしてユーザーを識別すれば良いということとなりますが、SYA + SYA
などの組み合わせだと、情報の取得は難しいですが弱点が同じなので、似た手口を使われるだけで一気に2種類の情報を取得されてしまう可能性もあります。
そのため、これらのうちそれぞれ違う種類のものを使おう、というのが 「2要素認証」や「多要素認証」という考え方です。
この考えを取り込むことでより安全なサイトを作れます。
まずは2段階認証、2要素認証を取り入れよう
具体的にはAmazon Cognito[3]、Google Identity Platform[4]、Auth0[5]、HENNGE ONE[6]、Ory[7]などを利用することとなると思います。
これらは複数機能を有しているのでわかりにくいかもしれませんが、多要素認証さえできればセキュリティ強度はぐんと上がります。
また、今後サービスが大きくなっても引き続き利用できるはず。
しかし、これらのツール導入に際し、おそらく今までDBで保存してきたであろうユーザー情報を移行しなければならないのが大きなハードルとなります。
ここは慎重に行うべきなので、一時的にDBと新システム両方にデータを保存するなど、アプリの変更が必要になるはずです。ここは気合いで乗り切るしかないので覚悟しましょう。
このユーザーの情報を格納し、提供するシステムを IdP(Identity Provider) といい、これをサービスとして提供しているものを IDaaS と呼んだりします。
今回大規模な引越しとなってしまいますが、SCIM(スキーム)というものに対応してしるツールを使えば今後はユーザー情報の引越しが楽になるのではないかと思います。
複数サービスを持ち始めたらSSOを検討する
まだサービスが単一で、複数のサービスを跨いでユーザーを識別する必要がなければここまでの対応で十分でしょう。
しかし、複数サービスまたはアプリとなってしまった場合はSSOにも対応させるのが良いかと思います。
SSO(シングルサインオン) は、「一回ログインしたら他の関連したサービスに毎回ログインしなくてよくなるシステム」です。
これを実現するのには SAML か OIDC の2種類の方法があります。他にも「RADIUS」や「KERBEROS」などもSSOを実現する仕組みですが、WEBアプリケーション用途ではないので先の2種類から選択します。
OIDC(OpenID Connect)は、OAuth2.0をベースにした「認証」の仕組みです。
その元となった OAuth2.0 は「認可」を実現するための仕組みです。
Oauth1.0や1.0aなんてバージョンもありますが、策定が甘かったので2.0が主流です。バージョン数がついてますが気にしなくていいです。
SAMLとOIDCの大きな違いは扱っている言語の違いです。
SAMLがXML、OIDCがJWTと言われる作り方の決まったJSON形式で情報をやりとりします。
あとは、SAMLがサーバーに重きをおいた設計、OIDCがクライアントに重きをおいた設計となっている...ぐらいしか違いはない、と今のところは思っておいて大丈夫だと思います。
基本的にユーザーの認証についてやれることは同じですが、SAMLならサーバーサイドでしっかり管理するが、XMLのデータの扱いは重くドッシリとしたイメージ。
OIDCはJWTが軽量なのでクライアント側の自由度が高い代わりに、防御力が若干低くライトなイメージをしていただければ。
またそれぞれの認証情報は変換もできるのでどちらを選んでもなんとかなる場合があります。
サービスの性質によって、より強固なセキュリティ要件があるならSAML、実行速度や利便性重視、SPAやスマホアプリならOIDCという感じでいいかも。
お堅い業種のシステムであればSAML一択にはなるかと。
詳細を見ていくと全く違うし、SAMLとOIDCをどう実装するかを書くとさらに話が長くなるのでここでは触れませんが、現段階ではこれだけの知識でいいと思います。
これらの導入関しても多要素認証実装時に使ったツールで両方使える場合が多いので、 (若干OIDCの方が実装が複雑な印象がありますが)、あとはツールをちょこちょこいじるだけでなんとかなるのではないでしょうか。
ここからさらにサービスが複雑化して、複数サービスで行える操作と行えない操作が出てくるならば、より認可の設定をしっかり作り込んでいく、となると思います。
ここで「認証」と「認可」について
最後で急に「認証」と「認可」について触れますが、これらには大きな違いがあります。字は似てるのに。
- 認証 (AuthN: Authentication):
- 「あなたは誰か」を調べること。逆にその人に何ができるかは気にしない。
- 例えると「社員証」のようなもの。ある会社の人間であればセキュリティゲートは通過できる。その人が社長の部屋に入れるかどうかはチェックしない。
- だれかを証明しているので「認証」。
- 認可 (AuthZ: Authorization):
- 「何をしていいか」を調べること。逆に誰かかどうかは気にしない。
- 例えると「乗車券」のようなもの。券によって自由席に座れるか指定席に座れるは決められていますが、持っていれば誰でも使えます。
- 動ける範囲を許可しているので「認可」。
免許証は「本人であるか」の情報と「どの車が運転できるか」の情報が書かれているので認証と認可が混ざった証明書となります。
このあたりの仕組みを考える上で多く出現し、大きな間違いや混乱を招くので知っておいて損はないです。
OAuthは認可と先ほど述べましたが、具体的にはX(旧: Twitter)で「このアプリの連携を許可しますか?」というところなどで使われています。
連携を許可するのにパスワードとかを入力するので認証とごっちゃになりがちですが、認可する側からしたらアカウントがあるかぐらいしか確認していなく、本人は誰であるかまでは気にしてないので「認可」です。
連携した先のアプリで本人の情報が表示される場合もありますが、あくまでも「連携アプリがユーザーの情報をとってくること」を認可されて使っているだけです。
パスキーについて
全然文脈関係ないですが、 最近では「パスキー」が主流になり、対応しているところが増えてきました。
パスキーとは「パスワード」ではなく代わりに鍵(SYHですね)を使おうとするもので、「パスキー」と呼ばれます。
色々なサービスでは登録時(または後から設定でも)パスワードを作成して登録していると思います。
これを「ワード」ではなく電子的な「鍵」に置き換えます。
鍵がSYAである指紋を元に作ったり、スマホの中で計算して作ったりします。 計算して作る場合は、まずQRコードなどを読み込んでそれを元にスマホの中で生成と保存がされます。
ログインする時はパスワードを入力していたように、指紋で鍵を作っていたならその指紋で認証。計算して作った場合は、鍵を作った時のスマホをかざしたりQRコードを読みとったりすることで、再計算してログインします。
計算で作られた鍵はスマホの中から基本は動かせない(=スマホが鍵になる)ので、そのスマホをなくすと鍵を無くしたこととなることに注意です。
終わりに
ログイン、いわゆる認証と認可についてざっくりとした話と実装の順番について書いてみました。
まだまだID/Passwordだけで実装されているサービスが多く、これからはどんどんセキュリティ要件も高くなっていくと思うので早めに二要素認証できるくらいまでは対策しておきたいですね。
以上となります。
NE株式会社のエンジニアを中心に更新していくPublicationです。 NEでは、「コマースに熱狂を。」をパーパスに掲げ、ECやその周辺領域の事業に取り組んでいます。 Homepage: ne-inc.jp/
Discussion