これは、筆者の「2025振り返り用ひとりアドカレ」記事の一つです。
はじめに
本記事は、フロントエンドに携わっている筆者がwebセキュリティを学習した際にメモ書きしていたものを体系的にまとめ直した内容です。
かなり長くなったので7記事のシリーズとして投稿していきます。
これまでの開発において、エスケープ処理やサニタイズ、アクセス制御などセキュリティを意識して行ってきましたが、そもそも「どういった経緯で、どうなる(なってしまう)から、どのような対策が必要となるか」を深く理解できていない自覚がありました。
そこで【フロントエンド開発のためのセキュリティ入門 知らなかったでは済まされない脆弱性対策の必須知識】をベースに生成AIも使いながらインプットしていきました。
もちろん今でもまだまだだと思っていますし、本記事は備忘録の側面が強いかもしれませんが、初学者をはじめ、筆者のようにセキュリティ対策の重要性は理解しているがどこか表層的な部分に留まっているかもというような方々に少しでも役立つように書いていきたいと思います。
シリーズ目次
- 第1回:Web通信の基礎知識
- 第2回:オリジンとCORS
- 第3回:サイドチャネル攻撃とSite Isolation
- 第4回:XSS(クロスサイトスクリプティング)
- 第5回:CSP(Content Security Policy)
- 第6回:CSRF、クリックジャッキング、その他の攻撃
- 第7回:認証・認可とセキュアな実装(本記事)
認証・認可
認証と認可の違い、分かりそうで分からないものの代表例でもあると思います。
Authentication: 認証(あなたは誰?)
ユーザーが本当にその人であるかを確認するプロセスで、誰がアクセスしているかを判別することが目的。
- 例:ログイン機能、多要素認証、二段階認証、生体認証
認証の種類
SMS認証
ログインに必要なリンクやパスコードなどの情報をSMSで送信し、ユーザーが受信したメッセージ内の情報を使ってログインする認証方法
ソーシャルログイン
GoogleやGitHub、Xなど各種ソーシャルサービスのアカウントを使ってログインする認証方法
FIDO(Fast IDentity Online)
パスワードの代わりに、生体認証やPINなどで「デバイスそのもの」を本人確認し、そのデバイス内で生成・保管された公開鍵と秘密鍵を使って認証を行う仕組み。
秘密鍵はデバイスの外へ出ないため、パスワード漏洩やフィッシングに非常に強い認証方式となっている。
WebAuthn(パスキー)
FIDOの発展版「FIDO2」をWebで利用するために W3C が策定した仕様で複数のブラウザで実装されている。
WebAuthnは「パスキー(Passkeys)」の技術的基盤となる仕様でもあり、現在 WebAuthnという土台の上に、各社がパスキーという形で実装を進めている。
パスワード認証に対する攻撃
ブルートフォース攻撃(総当たり攻撃)
色々な組み合わせのIDやパスワードをひっきりなしに入力して突破しようとする攻撃。
これの副次的効果として、ターゲットサイトをアクセス過多にして処理負荷からダウン(サーバの処理対応量を超過させて処理できないようにする)させるDDoS攻撃・DoS攻撃もある。
※ただし、ブルートフォース攻撃の主目的はログイン突破です。
辞書攻撃
一般的な単語や予測可能なID・パスワードを網羅的に入力して突破しようとする攻撃。
パスワードリスト攻撃
過去の漏洩データから得られた実際のID・パスワードを用いてログインを試みる攻撃。
リバースブルートフォース攻撃
パスワードを固定してID入力に総当たり攻撃してくる攻撃手法。この攻撃の場合、従来のログイン試行回数制限による対策では防御が困難となる特徴がある。
Authorization: 認可(どのような権限を持っている?)
認証済みのユーザーがどの操作やリソースにアクセスできるかを確認するプロセス。許可されていない操作は拒否される。
- 例:未ログイン状態(他人の投稿の一部閲覧のみ)、ログイン状態(他人の投稿閲覧をはじめ、自身の投稿や編集など)
つまり、認証とは「人物(ユーザー)の特定・認識」で、認可とは「特定人物を認識した上で、そのユーザーに許された操作行為(権限)」となります。
ログイン情報の漏洩に注意する
ユーザー情報を入力するページにおいて、Web解析ツールの導入は慎重に
EFO:Entry Form Optimization(エントリーフォーム最適化)の観点から、フォームにWeb解析ツールを導入しているところも少なくないでしょう。
しかし、 ユーザーの入力したセンシティブ情報がWeb解析業者に(誤って)送られるケースもあることを想定しておくべきです。
フォームへのWeb解析ツール導入時は設定を変えたりして、Web解析サービスにデータが送られないようにするのも情報漏洩のリスクヘッジとなります。
ブラウザへのセンシティブ情報の保持は慎重に
Cookieの取り扱い
ログイン情報やアクセストークンをブラウザに保存しておけば、再度Webアプリケーションにアクセスした時もログイン状態を維持できます。
ログイン状態を把握する「セッションID」や「トークン」の保管場所には、古くからあるCookieが選ばれることも多いです。
しかし、通信が盗聴された時やXSS攻撃でログイン情報やアクセストークンが漏洩するリスクもあります。
- XSS(クロスサイトスクリプティング)
攻撃者が悪意のあるスクリプトコードを正規のWebサイトに注入し、そのサイトを閲覧する他のユーザーのブラウザで実行させる攻撃。
機密情報の漏洩、Webアプリケーションの改ざん、意図しない操作、なりすまし(ユーザーの機密情報の窃取)、セッションハイジャック、フィッシング攻撃のリスクが生じる。
そこで、 ログイン情報やアクセストークンをCookieに保存する際には以下のような設定を行ってカバーしておくのがベターです。
1. HTTPS接続でしかCookieを送信しないように制限するSecure属性を設定
2. JavaScriptではアクセスできないように制限するHttpOnly属性を設定
Webストレージ(localStorage,sessionStorage)使用時の注意点
Webストレージに保存されたデータは同一オリジンポリシーによって制限されており、データを保存したオリジンと異なるオリジンはそのデータにアクセスできません。
- 同一オリジンポリシー
ブラウザに組み込まれているアクセス制限の仕組みです。
異なるwebアプリケーションとの間に境界(オリジン)を設けるブラウザの機能によって、開発者は特別な対策をしなくともwebアプリケーションからのアクセスを制限できます。
ブラウザはデフォルトで同一オリジンポリシーを有効にしていて、以下のようなアクセスは制限されます。
- JavaScript を使ったクロスオリジンへのリクエスト送信
- JavaScript を使った iframe内のクロスオリジンのページへのアクセス
- クロスオリジンの画像を読み込んだ 要素のデータへのアクセス
- Web Storage や IndexDB に保存されたクロスオリジンのデータへのアクセス
※他にも制限される機能はいくつかあります
※クロスオリジン:スキーム、ホスト、ポート番号のいずれかが異なる場合はクロスオリジン(Cross-Origin) となります
しかし、Webストレージに保存したデータはJavaScriptからのアクセスを制限できないため、WebアプリケーションにXSS脆弱性があるとデータ漏洩のリスクが高まります。
この点、XSS脆弱性があったとしてもHttpOnly属性を設定した Cookie だとセキュリティ面での安全性が高いですね。ただし、すべてのケースで Cookie が万能というわけではなく、設計や構成によって安全な保管方法の最適解は変わる点にも注意が必要です。
他にも例えば、APIサーバとフロントエンド用のサーバが分かれているような場合に、リクエストを受ける側のサーバ(APIサーバー)では(フロントエンド用のサーバーが発行した)トークンや Cookie を保持または妥当性の検証ができません。
このようなケースでは Double Submit Cookie(二重送信クッキー) が一つの対策として検討できますが、ログイン情報などはWebストレージに保存せず、必要な時にサーバへ都度問い合わせる方が安全 です。
-
Double Submit Cookie(二重送信クッキー)
ブラウザのCookieにトークンを保持させる方法
Webストレージ保存を実装する開発者に必要な意識
ログアウト時にWebストレージの情報を削除する処理を実装していても、実装または考慮漏れから「想定外の操作によってWebストレージにセンシティブ情報が残ってしまう」というケースも考えられます。
ログイン情報や機密情報が残ってしまった場合、XSS脆弱性によって情報漏洩するリスクがあるでしょう。
他にも、職場やネットカフェなどの共有PCのlocalStorageにそれら情報が残っていると、他の利用者が情報を盗み見ることも可能となってしまいます。
開発者はこのようなリスクと危険性を意識しながらWebストレージに保存していいデータかどうかを慎重に検討する必要があります。
さいごに
このシリーズでは、フロントエンド開発におけるセキュリティの基礎から実践的な対策まで、7回にわたって解説してきました。
1回目の冒頭でも書きましたが「セキュリティの動向は時代背景や技術進歩、攻撃手法の変化から年々変わるものという意識を持つ」のが大事だと考えています。
筆者も今後継続的にキャッチアップしていきたいと思います!
ここまで読んでいただき、ありがとうございました。
筆者の知識・経験不足から間違った点や、誤解を招きかねない表現がありましたらご教示・ご指摘いただけますとありがたい限りです。
書籍【フロントエンド開発のためのセキュリティ入門 知らなかったでは済まされない脆弱性対策の必須知識】への感謝
セキュリティ関連は裾野があまりに広すぎてどこから取りかかれば迷っていました。
そういった中でフロントエンドを軸にしてセキュリティ関連の情報や知識を体系的に教えてくれたのが本書でした。感謝したいと思います。
筆者のシリーズ記事では当書籍をベースにしてはいますが、筆者の主観で情報を取捨選択しているところがあるので是非ご自身でも書籍を手にとってみてください。
おまけ:パスワード入力時のUXを向上させるフォームづくりのTips
パスワード入力時のUXを向上させるフォームづくりのTips
<input type="password">は入力すると*で視認できなくなるので、「パスワードを確認」や「目のアイコン画像」を用意してユーザーがそれをクリックすると<input type="text">となって視認できるようにすることでUXを向上させられる。
- 実装例
const passwordInput = document.querySelector('input[type="password"]');
const toggleButton = document.querySelector('button.toggle-password');
const eyeIcon = document.querySelector('#eyeIcon');
const eyeOffIcon = document.querySelector('#eyeOffIcon');
toggleButton.addEventListener('click', () => {
const isPassword = passwordInput.type === 'password';
// inputのtypeを'text'と'password'で切り替え
passwordInput.type = isPassword ? 'text' : 'password';
// アイコンの表示も切り替え
eyeIcon.style.display = isPassword ? 'none' : 'block';
eyeOffIcon.style.display = isPassword ? 'block' : 'none';
// フォーカスを維持してUXを向上
passwordInput.focus();
});