237
194

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

意外と知られていないログインの裏側 - Webアプリケーションの認証の仕組み

237
Posted at

はじめに

自分でホームページを作ってログイン機能を実装しようとした時、こんな疑問に直面したことはありませんか?

  • パスワードをそのまま保存していいの?
  • ログイン後、URLを直打ちしたらログインせずに入れてしまうのでは?
  • そもそも「ログインしている状態」ってどうやって維持されているの?

普段何気なく使っているログイン機能ですが、その裏側には意外と知られていない仕組みがあります。この記事では、ログイン認証の基本的な仕組みについて解説します。

HTML/CSSだけではログイン状態を管理できない

実は、HTML/CSSには元来ログイン状態を確認する機能がありません

もう少し正確に言うと、Webの基盤となっている HTTPプロトコル自体が「ステートレス(状態を持たない)」 という性質を持っているためです。

HTTPのステートレスとは?

HTTPは、クライアント(ブラウザ)からサーバーへのリクエストごとに独立した通信を行います。つまり:

  • 1回目のリクエスト:「ログインページください」
  • 2回目のリクエスト:「マイページください」

この2つのリクエストは、HTTPの仕組み上は全く関係のない別々の通信として扱われます。サーバーは「さっきアクセスしてきた人と同じ人だ」ということを自動的には認識できないのです。

image.png

これでは「ログインした状態」を保つことができません。では、実際のWebサイトはどうやってログイン状態を維持しているのでしょうか?

Cookieとセッション管理の仕組み

答えはCookie(クッキー)とセッション管理にあります。

Cookieとは?

Cookieは、サーバーからブラウザに送られる小さなデータで、ブラウザに保存されます。そして重要なのは、ブラウザは保存したCookieを次回以降のリクエストで自動的にサーバーに送り返すという点です。

この仕組みを使って「ログインしている状態」を維持します。

セッションIDによる認証フロー

具体的な流れを見ていきましょう

image.png

ポイント

  1. ログイン時:サーバーはランダムな文字列(セッションID)を生成し、データベースに保存
  2. Cookieで送信:そのセッションIDをCookieとしてブラウザに送信
  3. ブラウザが保存:ブラウザはCookieを保存
  4. 以降のリクエスト:ブラウザは毎回Cookieを自動的に送信
  5. サーバーが検証:サーバーはセッションIDの有効性を確認して認証

URL直打ち問題の解決方法

「ログイン後のページのURLを直接入力したら、ログインせずに入れてしまうのでは?」という問題は、サーバー側でのセッション検証によって解決されます。

セキュリティのポイント

  • 全ての保護されたページで必ずセッション検証を行う
  • セッションには有効期限を設定する
  • 無効なセッションの場合は必ずログインページにリダイレクトする
  • クライアント側(JavaScript)だけでなく、サーバー側で必ず検証する

これにより、ログインをしているかどうかの判定が常に行われ、未認証のユーザーは保護されたページから弾かれるという仕組みです。

他にもあるセキュリティ上の注意点

ログインの仕組みについて分かってきたところで、大切なセキュリティの話もしておきます。
セキュリティに穴があれば他人に成りすまされたり、個人情報を根こそぎ持っていかれてしまいます。

実装が動くことと安全であることは別物なので、最初から安全性を前提に設計する意識が重要です。

1.パスワードは平文で保存してはいけない

なぜ平文保存がダメなのか?

もしパスワードをそのまま(平文で)データベースに保存していた場合

-- ❌ 絶対にダメな例
INSERT INTO users (email, password) 
VALUES ('user@example.com', 'mypassword123');

こうなると

  1. データベースが漏洩した場合、全ユーザーのパスワードが丸見え
  2. 管理者や開発者がユーザーのパスワードを見れてしまう
  3. 他サイトで同じパスワードを使っている場合、そちらも危険に

ハッシュ化による安全な保存

パスワードはハッシュ関数を使って一方向変換(ハッシュ化)してから保存します。
ハッシュ化がよくわからない人は簡単に、「元に戻せない形で変換している」 と覚えてください。

暗号化は復号可能ですが、ハッシュ化は一方向変換で復号不可能です。

// 擬似コード例
const bcrypt = require('bcrypt');

// ユーザー登録時
const password = 'mypassword123';
const saltRounds = 10;
const passwordHash = await bcrypt.hash(password, saltRounds);

// データベースに保存
db.query(
    'INSERT INTO users (email, password_hash) VALUES (?, ?)',
    ['user@example.com', passwordHash]
);

// 保存される値の例: $2b$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy

ハッシュ化の特徴

  • 一方向変換:ハッシュ値から元のパスワードを復元できない
  • 同じ入力→同じ出力:同じパスワードは同じハッシュ値になる
  • わずかな違いで大きく変わる:似たパスワードでも全く異なるハッシュ値に

2.Cookieに機密情報を保存してはいけない

CookieにはセッションIDのみを保存し、個人情報や機密情報は保存しません。
個人情報や機密情報を入れると毎回ネットワークに送られるデータとなり、漏えいのリスクが高まります

httpOnlyでなければJavaScriptから盗まれたり
secure未設定ならHTTPSでない経路で漏れる可能性があります。

Cookieにも適切なセキュリティオプションを設定した上で、機密情報はデータベースに保存するようにしましょう。

Cookieのセキュリティオプション

オプション 説明
httpOnly JavaScriptからのアクセスを禁止(XSS対策)
secure HTTPS通信でのみCookieを送信
sameSite クロスサイトリクエストでのCookie送信を制限(CSRF対策)
maxAge Cookieの有効期限を設定

3. HTTPS通信の必須化

セッションIDはHTTPS通信で送信しないと、中間者攻撃で盗まれる可能性があります。
HTTPでの通信は暗号化されていないので、いくら最終的な形が暗号化されていても途中で盗まれてしまえば機密情報が漏洩してしまいます。

4. セッションハイジャック対策

セッションハイジャックとは、セッションIDを盗んで正規のユーザーに成りすます攻撃です。
いくらパスワードが無事でもセッションIDが分かれば、保護されたページにもアクセスできるようになります。

そして先程の説明の通り、セッションIDはCookieで管理されているのでパスワードに比べて安全性が低いです。

その為、セッションIDについても以下のようなセキュリティ対策を取る必要があります。

  • セッションIDは十分にランダムで推測不可能なものにする
  • ログイン成功時にセッションIDを再生成する
  • セッションに有効期限を設定する
  • ログアウト時は必ずセッションを破棄する

まとめ

  1. HTTPはステートレスなので、状態管理には工夫が必要
  2. Cookie + セッションIDでログイン状態を維持
  3. パスワードは必ずハッシュ化してデータベースに保存
  4. セッション検証により、URL直打ちでも不正アクセスを防ぐ
  5. Cookieには機密情報を保存しない(セッションIDのみ)
  6. HTTPS通信と適切なセキュリティ設定が必須
237
194
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
237
194

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?