具体例で学ぶ、LINE Loginを利用した安心・安全な認証・認可機能の実装方法

尾上良範氏(以下、尾上):「具体例で学ぶ、LINE Loginを利用した安心・安全な認証・認可機能の実装方法」というタイトルで発表いたします。LINE株式会社の尾上と申します。よろしくお願いします。

まず簡単に自己紹介します。Developer Product2チームというところで、LINE LoginやLINE Front-end Framework、通称LIFFの開発の担当をしています。主な担当コンポーネントはサーバーサイドアプリケーションですが、複数のコンポーネントに跨って実装が必要な機能については全体方式の設計なども担当することが多くあります。

では今回のアジェンダです。まず1つ目がLINE Loginの紹介です。こちらは標準的なソーシャルログインの機能に加えて独自機能がいくつかありますので、それらについて簡単に説明を差し上げます。そして2つ目。こちらが今回の発表の本題です。私がLINE Loginの開発・運用をしていく中で、実際に目にしたセキュリティの事例について発表したいと思います。

セキュリティに関する話題は難しくなりがちですが、なるべく平易な言葉でわかりやすくお伝えできればなと思います。より詳細な情報が必要な場合は弊社のLINE Developersのサイトですとか、他にあるWebの情報ですとか、あるいは正確な情報が必要であればRFCなどを見ていただければいいかなと思います。

また今回の内容は実際に目にした実例ばかりですので、セキュリティに詳しい方であってもそうでない開発者がやりがちなことについて把握しておくのに役立つかなと思います。事前の案内ではプライバシー保護とID体系についてとあったと思いますが、こちらは時間の都合で割愛いたします。

LINE Loginの動き

ではまずはLINE Loginの紹介からです。いわゆるソーシャルログインサービスです。準拠している業界の標準仕様としてはOAuth 2.0ですね。社外向けにはAuthorization Codeフローを提供しています。内部的にはこれから出てくるオートログイン機能ですとか、LIFFのための認証・認可などについてはImplicitフローやOAuth 2.0の拡張仕様であるPKCEを利用しています。

そしてもう1つ。OpenID Connectにも準拠しています。OpenID Connect FoundationのCertificationプログラムの認定も受けています。

ソーシャルログインについてあまり予備知識がない方もいらっしゃると思うので、簡単に、どういった画面の動きをするのかを左側に出ている動画で説明しようと思います。

こちらは弊社が提供しているLINEのタイムラインのWeb版です。今はまだログインしていない状態ですね。タイムラインのログインのページが表示されていて、ログインしていないのでログインボタンが出ています。これをタップすると、LINEログインの画面に遷移します。ID・パスワードの入力画面があって、これらを入力してログインを押すとログイン処理が走ります。

またLINEのタイムラインのWeb版の画面に戻ってきて、今度はユーザーの持っている情報が表示されてログインしたことがわかります。

LINE Loginの便利な機能

LINE Loginには、こういった標準的な機能だけではなくて、多くの便利な機能が搭載されています。

数多くありますが、まず代表的なものとして、パスワードレスログインがあります。いくつかの機能がありまして、まず1つ目はQRコードログインです。そして2つ目がオートログインと呼ばれる機能です。こちらについてはこのあと簡単に説明します。

さらにまだまだ多くたくさんの機能がありますが、ここでは代表的なものを2つだけを簡単に口頭で説明します。

まず1つ目はボットリンクです。これはログインしたユーザーに、みなさんが開発したサービスのLINE公式アカウントをフォローしてもらう機能になります。ただログインしてユーザーの情報が取得できるだけではなくて、みなさんのサービスの画面を開いていないときでもLINE公式アカウントからログインしたユーザーに対してメッセージを送ったり、ユーザーからメッセージを受け取ったりして、ユーザーの方とみなさんのサービスとの間でコミュニケーションを図れるということになります。

そしてもう1つ目がLINE Profile+です。こちらはすべての社外の方に提供している機能ではありません。どういった機能かというと、ログインユーザーがあらかじめ LINEに登録した住所や電話番号などを、みなさんが開発したWebサイトのフォームなどに自動でフィルインする機能です。こちらは今機能のアップデートの予定をしておりまして、次回のLINE DEVELOPER DAYではまた発表ができるんじゃないかなと思います。

これ以外にもまだまだたくさんの機能がありますが、今日は簡単な説明にとどめるということで割愛したいと思います。詳しい内容については弊社のDevelopersサイトに機能が載っていますので、そちらを確認していただけるといろいろな機能が見つかるかと思います。

QRコードログインとオートログイン

では先ほど出てきたQRコードログインについて簡単に説明差し上げます。LINEのタイムラインのWeb版でもLINEログインの画面に遷移しますが、同じようにQRコードログインのボタンを押すことによってQRコードが表示されます。これをスマホのQRコードリーダーで読み取るとこのような画面が出てきて、ID・パスワードの入力なしでLINEのタイムラインにログインできるという機能です。

こちらはスマートフォン上のLINEアプリのQRコードリーダーで読み取ったものですが、LINEアプリがインストールされている端末であれば他のQRコードリーダーなどで読み込んでも問題なく動作します。

そして2つ目はオートログインですね。こちらはスマートフォン上のブラウザで、Webサイトに自動でログインするための仕組みです。LINEアプリがインストールされている端末であれば誰でも使うことができます。こちらも動画があります。これはLINE STOREの画面を例に説明していきます。ログインボタンを今押しました。そうすると一瞬だけLINEのアプリが表示されたと思いますが、これでもう認証はすでに完了しています。

試しにメニューを開くと、先ほどのログインのボタンがなく、マイページというのがあるので、ログインできている状態なのがわかると思います。

便利なのに追加の実装が必要ない

おそらく視聴している方々は開発者だと思いますが、開発者の視点としては、便利なのに追加の実装がいらないというところだと思います。通常のブラウザのLINEログインの実装さえしておけば、自動で動作するものになるので追加の実装は不要です。

あとは技術的な側面としては、先ほど軽くお話した通り、LINEのネイティブアプリとサーバーとみなさんが開発するWebサイトの間でセキュリティ的に問題ないような仕組みを使って情報をやり取りしています。

技術的な用語を挙げるとすると、OAuth 2.0の拡張であるPKCE仕様に似たメカニズムを使って安全性を担保しています。他にもセキュリティを担保する仕組みをいくつか入れています。

脆弱性とその影響範囲

ここまでが、LINE Loginの簡単な説明です。LINE Loginに便利な機能がたくさん備わっているのが理解していただけたと思いますが、扱う情報の特性上、脆弱性があった場合に個人情報が漏洩するなどのリスクがあり得ます。これ以降については実際に私が目にした4つのケースについて説明していこうと思います。

いずれも実例ばかりで、中にはものすごく頻繁に目にする事例もあります。LINE Loginに限らず、こちらはソーシャルログイン全般で発生しうる問題ですので、みなさんの参考になるかと思います。

実際の実例の説明に入る前に、今回の発表の対象範囲について定義しておきたいと思います。ここでは脆弱性を大きく2つに分けて分類しました。まず1つ目。こちらはLINE Loginなどのプラットフォーム自体に存在する脆弱性です。そして2つ目。こちらはLINE Loginなどのプラットフォームを利用するそれぞれのサービスで間違った実装をしてしまったことで発生する脆弱性です。

もちろん1つ目については我々プラットフォームの開発者が責任を持って最優先で取り組んで直ちに修正すべき内容です。ただLINE Loginのプラットフォーム自体の脆弱性をすべて修正したとしてもみなさんが開発するWebサイトで間違った実装をしてしまうと、脆弱性というものは依然として残り続けるということになります。今回の発表の対象としては後者の実例について解説していきたいと思います。

ソーシャルログインの仕組み

続きまして、実例に入る前にもう1つだけ説明させてください。まずソーシャルログインの仕組みについてご存知ない方もいらっしゃるかもしれないので、ものすごく単純化した事例で、簡単にどういった流れで処理が行われるのかを説明しようと思います。

まず1番です。エンドユーザーからみなさんが開発しているWebサイト、ここではyoursite.comという名前で書いています。こちらにログインのリクエストが投げられます。そうするとOAuth 2.0などのソーシャルログインの仕組みではLINE Loginのサーバーにそのリクエストがリダイレクトされます。リダイレクトされた先のページ上でエンドユーザーは、まず認証のためにID・パスワードの入力などをします。ここは先ほど出てきたQRコードログインなど、他の手段で代替することもあります。

次です。こちらは認証ではなくて認可のプロセスになると思いますが、yoursite.comに対して、私はデータのアクセスやある機能などの実行を許可しますよということをページ上の許可ボタンなどを押して、エンドユーザーがLINE Loginに伝えます。

これらの認証・認可のステップが完了すると、LINE Loginのサーバーはリクエストをまたリダイレクトしてyoursite.comに戻します。この際には先ほどエンドユーザーが同意したアクセス権限についての情報が含まれています。最後にこれらのアクセス権限の情報を使ってエンドユーザーのデータやエンドユーザーに対する何らかの処理をyoursite.comはLINE Loginのサーバーに依頼して実行するというかたちになります。

補足ですが、これはだいぶ単純化して説明したんですけど、5番目のところのアクセス情報というのはいろいろな受け渡し方がありまして、例えばOAuth 2.0のImplicitフローであれば、アクセストークンという6番で直接アクセス権限があることを示すために使われるような情報というのを直接手渡すこともあります。

またAuthorization Codeフローというものを使った場合にはアクセストークンを直接渡すというわけではなくて、Authorization Codeというテンポラリーな値を受け渡すことによって、よりセキュアにアクセストークンを取得するという仕組みになっていたりします。

またOpenID Connectの仕様では、5番のアクセス権限と先ほど説明したところにユーザーの認証情報を渡すこともできまして、IDトークンという形式で5番のところで一緒に渡すという仕組みもあります。

ケース1:クエリパラメータにアクセストークンが露出

さてさっそく本題の実例の解説に入りたいと思います。すでに画面に何か表示されていると思いますが、何かお気付きのことはあるでしょうか。こちらはLINE Loginの処理が完了したあとにあるWebサイトに戻ってきたときの状態です。見てすぐに気付かれた方もいると思うんですが、ここにaccess_tokenという怪しい文字が付いています。

もちろん、これだけ見て脆弱性があるかどうかはわかりませんが、私が見た実例では脆弱性がありました。どういったことかというと、まず、このクエリパラメータにアクセストークンが付いてしまっています。クエリパラメータというのは一般的に外部に漏洩しやすいものです。もしそれが漏洩してしまった場合、攻撃者はこの情報を使って先ほどのソーシャルログインの流れに従って簡単にユーザー情報を取得できてしまいます。

では攻撃者は具体的にどのように攻撃を行うのか。どんなサイトでもいいのですが、ここでは仮にExample StoreというECサイトがあったとします。ECサイトには、よくある機能だと思いますが、商品レビューのようなかたちでユーザーが投稿できるようになっていることが多くあります。攻撃者はこれらの仕組みを悪用します。

最初に攻撃者は、この攻撃者が管理しているevil.comという悪意のあるサイトのリンクをこのECサイトに貼り付けます。もちろんこちらからは一見悪意のあるサイトとはわからないような状態で貼り付けています。次に何も知らない被害者は、このリンクをそれとは知らずにクリックしてしまいます。

そうすると何が起きるかというと、このクエリパラメータ、このURLに今表示されている情報がRefererリクエストヘッダーとして攻撃者に渡ってしまいます。これにはクエリパラメータにアクセストークンを直接入れてあるので、アクセストークンの情報が攻撃者に渡るということになります。攻撃者はこのアクセストークンを使ってLINEログインのサーバーにアクセスして、ユーザー情報などを不正に取得できてしまいます。

ケース1の対策:アクセストークンを露出しない

ではどのように対策すればよいかというと、先ほどの説明の逆になるだけなんですけど、アクセストークンを露出しないようにしましょう。 ではどうやって取得するのかというと、さまざまな実装方法があると思います。ここでは簡単に3つだけ挙げました。

まずはサーバーのストレージに保存しましょうということですね。こちらは先ほど出てきたAuthorization Codeフローというのを使っていれば必然的にサーバーを経由するような実装になるのが自然ですので、こうされている方は多いと思います。サーバーサイドとブラウザとのやり取りについては独自のログインセッションなどを発行してCookieで情報をやり取りするのがいいでしょう。

2つ目はブラウザのストレージです。セッションストレージなどの揮発性の高いものを利用するのが一般的かと思います。ローカルストレージを使う方法もあるかもしれないですね。こちらはSame-Origin Policyなので他のドメインに情報が漏洩しないような仕組みもありますので、こちらを使うのがいいかなと思います。

サーバーサイドのアプリケーションがある場合はサーバーサイドのほうを使ったほうがいいのかなとは思いますが、SPAなどでそういったことがない状態では2番目を使うことになるのかなと思います。

3つ目がネイティブアプリケーションです。LINE SDKというものがLINE Developersのサイトで公開されていますが、そちらにLINE Loginを便利に使う機能などが用意されていまして、そちらを使えば、特に意識することなくトークンを保持できます。

ケース2:固定値のstate

ではケース2に移ります。こちらについても何かおかしいところ、怪しいところがあるかどうかを見ていただきたいと思います。こちらはあるサイトがLINE Loginを試みたときにLINE LoginにリダイレクトされたリクエストのURLになっています。実はここの中にはおかしなところというのは特にありません。

ただもう一度ログインしようとしたとき。これを見て何かお気付きの点はあるでしょうか。実はここのstateの値がまったく同じになっています。これは大きな問題があります。ではどういった問題があるかというと、stateというのがどういった役割でどういう働きをしているのかということを説明することによって解説していきたいと思います。

まずstateを正しく使った場合です。みなさんが開発しているLINE Loginを利用しているサービスyoursite.comが、ログインしようとしてきたユーザーにstateを発行します。ここで発行したstateは他の人には見えません。これを先ほどのソーシャルログインの流れに従って、リクエストがLINE Loginのサーバーにリダイレクトされます。

ここでログイン処理が完了すると、このリクエストにはstateの値というのが付与されて、またyoursite.comに戻ってきます。yoursite.comは何をすべきかというと、4番と3番のところでLINE Loginが追加して4番で戻ってきたstateの値というのを最初の1番で発行した値と同じかどうかをチェックします。

これをチェックすることによって本当にログインしようとしているエンドユーザー以外の誰かが介在して、1番とは異なるところから持ってきた情報をあたかも4番であるかのように見せかけてリクエストを送ってくることを防げます。

ケース2:CSRFアタックという攻撃手法

ではもしこのstateの値が固定の値だったらどうなるのか。攻撃者がどのように攻撃していくのかという手順で見ていきたいと思います。

こちらはCSRFアタックと呼ばれる攻撃で、よく名前をお聞きすることもあるかと思うんですが、こちらについて説明していきます。まず攻撃者はLINE Loginのサーバーにあたかもyoursite.comからのようなログインのリクエストであるかのようなリクエストを送り付けます。次に攻撃者は、LINE Loginの処理が完了した直後にブラウザ上の処理を停止します。

この状態ですとyoursite.comにはリクエストが通りません。次にEメールですとか、あるいは先ほどの例のようにWebサイトに情報を登録するなどして、被害者に2番のところで停止した処理を再開させようとします。攻撃者がそれとは知らずに2番で停止した状態のダイレクトのリンクをクリックしてしまうと、この被害者は攻撃者としてyoursite.comにログインしてしまうことになります。

そうすると何がまずいかというと、例えばyoursite.comというのが何らかのファイルなどを共有するサイトであった場合を考えると、例えばそうとは知らずに個人情報が大量に含まれているようなデータをアップロードしてしまうかもしれません。そうなってしまうと今攻撃者としてログインしていますので、攻撃者のものとしてデータが登録されます。そうなると当然攻撃者はこの情報を自由に取得できてしまいます。

ケース2の対策:stateのランダムな値とし露出を防ぎ確認する

ではどう対策すればいいかという話です。ほとんどこれまでで説明してしまった内容ですが、yoursite.comが何をすればいいかという点で、もう一度まとめます。

1番からです。まずは十分にランダムな値となっているstateを発行します。stateを発行したらブラウザのCookieなどの絶対に漏れないような場所、そのユーザーにしか見えないような場所にその値を保存します。

次に3番のところでstateの値をクエリパラメータとして付けて、LINE Loginにリクエストをリダイレクトします。そして最後の4番ですね。LINE Loginからリクエストがリダイレクトされて戻ってきたときに、この1番で発行したものと戻ってきたリクエストに付いているstateの値というのを比較して、それが違っていればログインを拒否します。こちらがケース2になります。

ケース2は非常によく見る事例ですので、こちらは気を付けて正しく実装されているかというのを確認していただくのが本当にいいと思います。