kouの技術的メモ

学習した内容の定着やアウトプット用に開設しました

ログイン周りとセキュリティ関連の情報収集

SPAでのログイン・ログアウト機能実装方法のベストプラクティスが分からなかった事と、脆弱性についての知識が不足しているので情報収集。

session認証とトークン認証の違い。

  • cookiesを使ったsession認証
    • Cookieとは、Webサーバーがクライアント(PC等)に預けておく極小さなファイル。クライアントがWebサーバーに初めて接続(Login)した際に、Webサーバーがクライアントに対してCookieファイル(SessionID)を発行し、HTTPレスポンスのヘッダを利用して送ります。その際に発行されたSession情報(SessionID)にはログイン情報が含まれます。
    • サーバにアクセスする度にクライアント側のリクエストヘッダに含まれるCookieファイル(session ID)とサーバ側に保存されているSessionID情報を比較して合致した際に認証されたとみなされる。
  • トークンを使った認証
  • Tokenによる認証も、Cookieと同じく、まずはクライアントがWebサーバーに接続(Login)した際に、Tokenが返されます。ただCookieと違ってあ、サーバーにその情報を保存はしません。「認証に成功した」というToken(いわゆる「認証情報」)を持ち、リクエストする度にリクエストヘッダにTokenを含んで送っています。

また、railsを使った認証系のセキュリティは以下も参考にします。

Railsアプリの認証システムをセキュアにする4つの方法(翻訳)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社

実装方法の検討

JWTとは

cookieとは別によくSPAで認証系で使われる技術としてJWTというものがある。

JWT・Cookieそれぞれの認証方式のメリデメ比較 - Qiita

Cookieはサーバ側でsession情報を持つ。CookieにはsessionIdを入れており、リクエストの都度sessionIdに紐づくサーバ側sessionデータを参照している。 Tokenはクライアント側で「認証に成功した」という情報(=Token)を持ち、リクエストの都度それを送る。

SPAの認証方法

SPAを使った認証系は(OauthやSSOを除く)大まかに4つに別れる

  1. サーバー: Sessionトークンを発行 -> クライアント: Cookieに保存
  2. サーバー: Sessionトークンを発行 -> クライアント: Web Storageに保存
  3. サーバー: JWTを発行 -> クライアント: Cookieに保存
  4. サーバー: JWTを発行 -> クライアント: Web Storageに保存

4の様にSPAではフロント側にセッション情報やJWTを保存する際HTML5の新機能local storage(web strage)と呼ばれる領域を使ってブラウザ側に保存するパターンも多いらしいのですが、下のリンクの様にセキュリティ上脆弱性を孕む(scriptを使うと簡単に中身を覗ける)様です

HTML5のLocal Storageを使ってはいけない(翻訳)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社

local storageはあらゆるJavaScriptコードから自由にアクセスできてしまいます(データ保護的なものはありません)。これはセキュリティ上非常に重大です。

webサイトに悪意のあるJavaScriptが埋め込まれたサイトの外部リンクなどを使って、local strage上のデータを全てコピーする事もできます。

とのことでXSSクロスサイトスクリプティング)攻撃で簡単に情報を取られる危険性があり、セキュリティ上認証情報をweb storage保持しておくのは望ましくないとのことで、2と4はやめます。

残る1と3ですが、cookieでhttpOnly属性をtrueにすれば、JavaScriptからcookieにアクセスできなくなるのでXSSの被害を緩和できます。(JavaScript の Document.cookie API にはアクセスできなくなる)

調べた結果JWTである理由も今回は特に無いと思いますので、

普通に1のセッションをcookieを使って実現したいと思います。

また、その場合CSRFは防げないためcookieのセッションIDとは別にCSRFトークンも実装します。

Railsの場合、例えばフォームでpostするときは自動的にトークンが生成されブラウザサーバ間でCSRF対策がなされるのですが、APIの場合は自分で対策しなくてはいけません。

最初はCORS (Cross-Origin Resource Sharing)の設定で許可されたオリジン以外のからアクセスは弾かれるので、CSRFトークンは必要ないのではないかと思いましたが、CORSはサーバへのアクセスを防ぐものではなく、サーバからのレスポンスをクライアント側で読めなくするものなので、CSRFによるサーバへの不正なリクエスト自体は成功してしまいます(例えば罠サイトで情報を書き換えようとして不正なPostリクエストを送った場合でも、レスポンスは帰ってこないが、このPost自体は成功してしまう)

APIドメインが認証用Cookieドメインと同じ場合:CookieのSameSite属性をLaxに指定 APIドメインが認証用Cookieドメインと異なる場合: CookieのSameSite属性をNoneに指定し、Secure属性を付与する CSRF tokenを利用する

cookieの属性

cookieはいろんな属性がありますが、セキュリティに関連する設定属性は以下になります。

  • Secure属性
  • trueの場合CookieHTTPS通信でしか送受信されない。
  • HttpOnly属性
  • JavaScriptからcookieにアクセスや操作をすることが出来ない
  • SameSite属性
    • Lax、Strict、Noneの3つの属性があり、リクエスト元によってそのCookieを送信するか否か決める。

参考にした書籍、情報

徳丸 浩 『安全なWebアプリケーションの作り方』

安全なウェブサイトの作り方:IPA 独立行政法人 情報処理推進機構