01 — 構成
クライアントからDBまでの経路
アプリはインターネット上の固定IPやポート開放を一切使わず、Tailscale Funnelが発行する1つのURLだけを通じてサーバーと通信します。
クライアントは 公開IPを持たないサーバー に、Tailscale Funnelが払い出すmix2k.icefish-ayu.ts.netという1つのURL経由でのみ到達する。DB接続情報とトークン署名鍵は、Webから読める場所(/var/www/html)の外に置かれている。
Why Funnel
サーバーはTailscaleのプライベートネットワーク(tailnet)の中にしか存在せず、ルーターのポート開放も固定グローバルIPの取得もしていません。
Funnel機能がmix2k.icefish-ayu.ts.netというHTTPS URLを生成し、そこ宛のリクエストだけをトンネル越しにサーバーへ届けます。公開範囲を1つのホスト名に絞れるため、個人運用のサーバーでも安全に外部公開できます。
02 — 認証
ログインからAPI呼び出しまでのトークンの流れ
セッションCookieではなく、ログイン時に発行される署名付きトークンを毎回のリクエストに添えることで本人確認しています。
トークンはログイン時に一度だけ発行され、以降は毎リクエストのAuthorizationヘッダーで検証される。8時間で失効するか、署名が合わない場合は401が返り、クライアントはその場でログイン画面へ戻す。
03 — 機能
役割ごとにできること
同じログイン画面から入り、アカウントの種別(一般ユーザー/管理者)に応じてメニューの内容が変わる。
一般ユーザー
type = 0
- 拾得物一覧の閲覧・カテゴリ絞り込み・キーワード検索
- 拾得物の詳細表示
- 落とし物のお問い合わせ送信(場所・日付・詳細情報)
- ログアウト
管理者
type = 1
- 一般ユーザーの全機能に加えて —
- 拾得物の登録(画像アップロード込み)
- お問い合わせ一覧の確認
- ユーザー登録(管理者権限の付与可否を選択)
04 — 設計
セキュリティ設計のポイント
パスワードはハッシュ化
password_hashで保存。旧・平文パスワードはログイン成功時に自動移行
秘密情報はWeb非公開の場所へ
DB接続情報・トークン署名鍵は/var/www/htmlの外に配置
管理者専用APIをサーバー側で強制
UIの表示制御だけでなく、auth.phpがtypeを都度検証
アップロード画像を検証
拡張子でなく実ファイルのMIMEタイプを判定し許可形式のみ受理
エラー詳細を外部に漏らさない
例外の内容はサーバーログにのみ記録し、汎用メッセージだけ返す
なりすまし防止
お問い合わせのuser_idはクライアント申告でなくトークンの持ち主を使用