Webアプリケーションのセキュリティ基礎
■第3話:認証とセッション管理のベストプラクティス
(最終更新日:2023.10.12)

(絵が小さい場合はスマホを横に)
「必要な人に必要な情報を」
認証とは、ユーザーが主張する身元を確認する過程を示す。
簡単に言えば「貴方は貴方ですか?」に答える行為である。
この過程で、パスワード、生体認証、トークン、様々な方法で人物を確認する。
今回は安全な認証方法について説明する。
これにより、その人に必要な機能や情報だけを提供することが可能になる。
1.認証と2要素認証 (2FA)
認証は、ユーザーが主張する自身のアイデンティティ(身元)が正確であることを確認する過程を指す。
通常、ユーザー名とパスワードの組み合わせを使用して、特定のシステムやサービスへのアクセスを許可された人物であることを確認する。
パスワードやPINコード、秘密の質問などを知識認証、
携帯の電話番号(SMSメール)やハードウェアトークン、ICカードなどを所持情報、
指紋、手のひら静脈、顔などを生体情報として分類でき、
これらの要素の内、2要素を使って認証することを2要素認証と言う。
パスワードと秘密の質問では2要素とならず、セキュリティ的には弱い。
2要素を組み合わせて、セキュリティを強化しよう。
実際、総務省は各自治体の業務端末への二要素認証を必須と定めている。
積極的に多要素認証(2要素以上の認証)を取り入れよう。
認証のための3つの要素
2.パスワード管理のベストプラクティス
パスワードの管理には、適切な取り扱いと安全な保存が不可欠である。
パスワードは平文のまま保存せず、ハッシュ関数を使用して変換されるべきである。
また、定期的なパスワードの変更や複数のサービスで同じパスワードを使用しないことも推奨される。
パスワードのハッシュ化はランダムなデータ(ソルト)と共にハッシュ値を生成する際に用いる。
PHPの関数、password_hash()では、関数の内部でソルトを生成し、強力なハッシュアルゴリズムを使うことができる。
パスワードのハッシュ化(PHP)
パスワードの検証にはpassword_verify()関数を使用する。
ハッシュ化したパスワードの認証
ソルトを用いてハッシュ化すると、同じパスワードでも異なるハッシュ値になる。
そのため、レインボーテーブル攻撃のリスクを低減できる。
レインボーテーブル攻撃とは、様々なパスワードの組み合わせでハッシュ関数を使用してハッシュ値を計算し、テーブルとして所有する。
テーブルの作成は非常にコストがかかるが、一度作成してしまえば、参照用として活用できる。
しかし、先ほどのようにソルトを用いると、各ソルト毎、各ユーザー毎にテーブル作成が必要となり、実質テーブル作成は不可能となる。
このような防御手段である。
レインボーテーブル攻撃から守るソルト
また、ユーザーは強いパスワードを用いるべきです。アプリケーション側である程度、使う文字の組み合わせを要求して強度を上げることができます。
実際には、数字、大文字、小文字、特殊文字を含む長いものであるべきだ。
短いパスワードや一般的な単語、連続した数字など、容易に推測可能なものは避けるべきです。
アルファベット小文字だけでの8文字で構成すると、268=208,827,064,576通り、
アルファベットの大文字、小文字で構成すると、528=53,459,728,531,456通り、
各種記号も含めるて構成すると、948=6,095,689,385,410,816通りとなる。
この数では分かりにくいが、2023年の最新CPUを搭載するPCを用いると、
アルファベット小文字は数分、大文字・小文字混合は数日、すべての文字を含むパターンは数カ月程度かかる。
なので、文字数を10文字程度まで必須とし、記号を含めた全ての文字を入力させるようにすれば、パスワードの強度的には充分だろう。
3.セッション管理とセッション固定攻撃
ウェブアプリケーションにおける「セッション」とは、ユーザーがログインし、ログアウトするまでの一連の操作や状態のことを指す。
これにより、ユーザーがページを移動しても、ログイン状態やカートの中身、設定などの情報を維持することができる。
セッションを管理する仕組みは、主にクッキーとデータベースで成り立つ。
クッキーはブラウザがユーザーのコンピュータに保存する小さなテキストファイルである。
ユーザーがウェブサイトにログインすると、サーバーは一意のセッションIDを生成し、これをクッキーとしてユーザーのブラウザに送信する。
ユーザーがそのウェブサイトの別のページに移動するたびに、ブラウザはこのセッションIDを含むクッキーをサーバーに送信し、
データベース上に保存したセッションIDと照合する。
これにより、サーバーはユーザーを認識し、そのユーザーのセッション情報を維持することができる。
セッションでユーザーを管理
ユーザーがウェブサイト内を自由に移動しても、ログイン状態やショッピングカートの内容、ユーザーの設定など、
ユーザー固有の情報や状態を維持することができる。
このセッションを盗む方法として、セッション固定攻撃がある。
攻撃者が自分たちで決めたセッションIDを含んだリンクを踏ませ、そのIDでセッションを作らせる。
そして、攻撃者は同じIDを用いて、その人になりすまして買い物なり、情報を盗む。
このような、セッション固定攻撃を受けないためにも、
セッションはサービス側がログイン毎に新しいものを発行したり、有効期限を短くして常に新しいものを供給することで防ぐことができる。
また、セッションハイジャックという攻撃方法もある。JavaScriptのコーディングに脆弱性があると、XSSにより個人のCookie情報を取得できてしまう。
他にも、Wifiなどから盗聴することで、Cookie情報を盗む。
セッションを盗まれないためにも、Cookieの設定を「HttpOnly(JavaScriptで操作させない)、Secure(HTTPSを必須とする、盗聴されない)、
Path(特定のディレクトリ下のみでCookieを送信する)、
SameSite(同じオリジン(ドメイン)のリクエストのみCookieを送信する)、有効期限を短くする」ことが大事である。
4.セキュアなトークン管理
トークンは、認証やセッション管理の際に使用される一時的なコードやキーを指す。
トークンは安全に管理され、漏洩や不正利用を防ぐための対策が必要だ。
例として、トークンは有効期限を持ち、一度使用されると無効化されるべきである。
また、トークンは暗号化され、安全な通信チャンネルを介して送受信される。
トークンの例としては、前項で説明したセッションもトークンになる。
他にもJSON Web Token、OAuth 2.0 トークン、リフレッシュトークン、ワンタイムパスワードトークン、CSRFトークンなどがある。
ここでは詳しく説明しないが、リフレッシュトークン以外は全て認証に関わるものである。
5.まとめ
今回、安全に認証する方法に関して、一通りの流れを紹介した。
パスワードのハッシュ化、セッション管理といった部分は、Laravel、Rails、Djangoといった主要なフレームワークが自動で行ってくれる部分である。
しかしながら、知識を身に着けておくことで、不測の事態にも対応することができる。
加えて、2要素認証やパスワードの強度設定は、セキュリティの強度を上げる上で重要である。
今回の内容は使う側にとっても重要なので、ぜひ自分なりに調べて復習しておこう。
▼参考図書、サイト
安全なウェブサイトの作り方
情報処理推進機構
キャノンサイバーセキュリティ情報局
Canon
ハッシュ化のソルト(salt)とペッパー(pepper)についてまとめた
Qiita
クッキーとセッション:サイト訪問者の情報を覚えておくための仕組み
Think IT