【AI駆動開発】高校生がAIと二人三脚で、RSA×AES暗号化&5段階リスク検知を盛り込んだガチの認証システムを自作した話
はじめに
こんにちは。たまに、Webサービスの開発をしている高校生です。
最近、自作のデジタルプラットフォーム「SHOHS」のログイン認証システムを一新しました。セキュリティ周りを妥協したくなかったので、フロントエンド完全E2EE暗号化や、大手のクラウド顔負けの「5段階リスク自動検知エンジン」を実装しています。
バックエンド(PHP)のベースは、私の設計のもとで生成AIに出力させましたが、マルチアカウント対応の際に発生した深刻な仕様のバグは、自分で原因を突き止めてコードを修正・ロジックを完成させました。
その開発プロセスと、AIのコードを人間がどうデバッグしたかの記録を共有します。
1. この認証システムに盛り込んだガチ機能
既存の認証ライブラリ(Auth0やFirebaseなど)は一切使わず、ゼロから「車輪の再発明」をしています。
① フロントエンド完全E2EE暗号化(RSA × AES)
ネットワーク上を生パスワードが流れるのを防ぐため、ブラウザ側(JavaScript)で公開鍵を使ってユーザー名・パスワードをRSA暗号化してPOSTし、バックエンド側(PHP)で秘密鍵を使って復号する設計にしています。これにより、万が一Apacheのアクセスログが漏洩しても、パスワードは絶対に漏れません。
② 5段階のリスク自動検知エンジン(5 Tier Risk Engine)
単なるパスワード検証だけでなく、バックエンドで以下の数値をリアルタイムに監視するエンジン(evaluate5TierRiskEngine)を組み込みました。
- 24時間以内の異なるIPアドレスからの同時アクセス数(アカウント共有・乗っ取り検知)
- 安全確認コード(2段階認証)の連続失敗回数
など...
怪しい挙動を検知すると、リスクレベルが自動で Tier 1 〜 5 までエスカレートし、ロボット確認(reCAPTCHA)を強制したり、自動でアカウントステータスを suspended(停止) にします。
2. AIコード特有の罠と、マルチアカウント崩壊バグのセルフデバッグ
AI駆動開発は爆速ですが、設計が高度(マルチアカウント対応 × ガチガチのセキュリティ)になってくると、AIも予期せぬエッジケースでバグを出します。今回一番苦労したのが、「2個目のアカウントにログインしようとすると、1個目のアカウントが強制ログアウトされる」という不具合でした。
発生していたコードの断片(修正前)
バックエンドのログイン成功時処理(onSuccessfulLogin)で、AIはセッション固定攻撃対策として以下のコードを出力していました。
function onSuccessfulLogin($conn, $account_id, $app_id, $redirect_url, $continue) {
global $_SESSION;
// セッション固定攻撃対策
session_regenerate_id(true);
// ... (このあとトークン発行や既知アカウント配列への追加処理)
}
原因の深掘り
PHPの session_regenerate_id(true) は、古いセッションファイルを完全に破棄します。これのせいで、同じブラウザで保持していたマルチアカウント用のセッション空間($_SESSION['known_account_ids'])がリセットされ、他アカウントがログアウトされていました。
そこで、まずセッションデータを一度変数に退避させて復元するアプローチを取りました。
$old_session_data = $_SESSION;
session_regenerate_id(true);
$_SESSION = $old_session_data;
しかし、これでもまだ他アカウントがログアウトされる問題が続きました。ここからが自分の手によるデバッグです。
真の原因:データベース内の session_id
このシステムのログイン判定は、データベース(login_history)に保存されている session_id と、現在のブラウザのセッションIDが一致しているかで判定していました。
session_regenerate_id(true) を実行すると、ブラウザ側のセッションID(クッキー値)自体が新しく書き換わります。そのため、1つ目のアカウントのDB履歴が「古いセッションID」に取り残されてしまい、システムがログアウト状態だと誤認していたのです。
最終的な解決策(自分で修正したコード)
ログイン成功時に、古いセッションIDで紐づいていた過去のログイン履歴も、新しいセッションIDへ一括でアップデートする処理を自分で追加し、ロジックを完成させました。
function onSuccessfulLogin($conn, $account_id, $app_id, $redirect_url, $continue) {
global $_SESSION;
// 1. セッションID変更 of 追従用データを取得
$old_session_id = session_id();
$old_session_data = $_SESSION;
// 2. セッションIDの再生成
session_regenerate_id(true);
$new_session_id = session_id();
$_SESSION = $old_session_data;
// 3. 【自分で追加】過去のログイン履歴のセッションIDも新しいIDに紐付け直す
if ($old_session_id && $new_session_id && $old_session_id !== $new_session_id) {
$stmt_up_sess = $conn->prepare("UPDATE login_history SET session_id = ? WHERE session_id = ?");
$stmt_up_sess->bind_param("ss", $new_session_id, $old_session_id);
$stmt_up_sess->execute();
$stmt_up_sess->close();
}
// ...このあと新規ログイン処理
}
この修正を入れたことで、セキュリティ強度(セッション固定攻撃対策)を極限まで高く保ったまま、シームレスなマルチアカウントの切り替えを完全両立させることができました。
おわりに(AI駆動開発をやってみて)
「AIが作ったコードなんて単純なものだろ」と思われるかもしれませんが、プロンプトの出し方や、例外処理の組み込み方次第で、個人開発でもここまで強固なシステムを形にできます。
そして何より、「AIが吐き出した高度なコードの挙動を理解し、その仕様の隙に生まれるバグ(今回のようなセッションIDの乖離など)を人間がロジックで見つけ出して修正する」 というプロセスこそが、これからの時代のエンジニアリングの楽しさだなと痛感しました。
裏側の泥臭いセッション管理やセキュリティ設計が大好物な諸先輩方、もし「ここをもっとこうすると堅牢になるよ」などのアドバイスがあれば、コメントで教えていただけると嬉しいです!