🛡️ セキュリティ対策
本ページは KASUGAI Canvas に実装されているセキュリティ対策と、現在判明している制限をまとめたものです。認証方式ごとの資産の秘匿範囲(.kasc・データ・静的ファイル)については 認証とプラグイン を参照してください。
デプロイ形態と信頼境界
提供される API は実行形態で分離されています。高権限 API(ファイル書き込み・プラグイン書き込み・fetch プロキシ・rclone 連携・シャットダウン等)はローカル Rust サーバー(127.0.0.1 バインド)でのみ有効です。公開環境(Cloudflare Pages/Workers・Cloud Run)には認証済みの保存系 API(/api/auth・/api/kasc・/api/data・/api/gemini)のみが存在し、無制限の書き込み・fetch プロキシは提供しません。フロントエンドは GET /api/capabilities の応答でバックエンド能力を判定し、機能を出し分けます。
サーバー配布 API キーの取り扱い
- Gemini API キー(秘匿):
GEMINI_API_KEYは Secret Manager 等に置き、/api/geminiがブラウザのリクエストに注入して転送します。キー自体はブラウザに一切現れません。認証モード時は kasugai トークン(Cookie またはAuthorization: Bearer)・Cookie・IAP のいずれかの資格情報が必須です。 - Maps Platform キー(配布):
GOOGLE_MAPS_API_KEYは/api/capabilitiesの応答でブラウザへ通知され、未保存時に localStorage へ自動登録されます。タイル URL に埋め込まれる設計上の公開キーのため秘匿はせず、保護は GCP の HTTP リファラ制限で行います(https://<配信ドメイン>/*のみ許可)。リファラ制限を付ければ第三者が奪取しても別オリジンでは使えません。
認証トークンと .kasc ファイル
- 方式3〜7 のセッショントークンは
expiry.HMAC-SHA256(expiry)形式で、KASUGAI_TOKEN_SECRETによる HMAC 検証・タイミングセーフ比較・有効期限 12 時間です。Cookie(kasugai_session)にはHttpOnly; Secure; SameSite=Strictを付与しています。 gs:///r2://のデータ参照は読み込み時に/api/data/...?token=…へ書き換えられますが、.kasc のエクスポート・クラウド保存時にはrestoreKascで元のgs:///r2://に復元されます。共有した .kasc にベアラトークンが混入することはありません。- BYO API キー(Gemini 等)は .kasc・共有ファイル・コードへの書き込みを禁止しています(
yahooappid:など仕様上キーを含める行は限定的に存在するため、配布前に確認してください)。
/api/data の Content-Type 固定(stored XSS 対策)
PUT /api/data/* で保存する Content-Type はリクエスト値を信用せず、GET 配信時にも拡張子由来の固定マッピングで返します(Workers/Pages Functions・Cloud Run 両方で同一方針)。保存済みオブジェクトに text/html が書き込まれていても、配信時に安全な型へ上書きされます。
| 拡張子 | 配信 Content-Type |
|---|---|
.geojson | application/geo+json |
.json・.topojson・.czml | application/json |
.kml | application/vnd.google-earth.kml+xml |
.csv・.tsv・.txt・.tif/.tiff・.png/.jpg/.jpeg/.webp・.mp4・.glb・.mvt/.pbf・.gpkg 等 | 各形式の既定 MIME |
.html・.svg・.js・.pmtiles・その他未知の拡張子 | application/octet-stream(ブラウザで実行・解釈されない) |
アプリ内のデータ読み込みは fetch 経由で Content-Type に依存しないため、実データ利用への影響はありません。
BYO API キーの取り扱い(外部エージェント)
「エージェント」設定の Send my Gemini API key(sendKey) を ON にすると、外部エージェントのエンドポイントへ BYO キーが同梱されます。この場合の送信先は以下に限定されます。
https://…— 常に許可http://localhost…・http://127.0.0.1…— ローカル開発用の例外として許可- その他の
http://…— リクエスト自体を送信前に中止します(平文でのキー流出防止)。sendKey が OFF の場合はエンドポイントに関係なくキーは同梱されません。
/api/fetch の SSRF 対策(接続先許可リスト)
ローカル版の CORS プロキシ GET/HEAD /api/fetch は、接続先がプライベート系アドレスの場合既定で 403 を返します。ホスト名指定は名前解決して IP で判定するため、http://社内ホスト/ のような指定も対象になります。
| 既定で拒否される範囲 |
|---|
ループバック(127.0.0.0/8・::1)、プライベート(10.0.0.0/8・172.16.0.0/12・192.168.0.0/16)、リンクローカル(169.254.0.0/16 — クラウドのメタデータエンドポイント含む・fe80::/10)、ULA(fc00::/7)、共有アドレス空間(100.64.0.0/10)、0.0.0.0・未指定アドレス |
社内 LAN の GIS サーバー等からデータを取得したい場合は、exe 隣の kasugai_canvas.fetch.json に許可リストを記述します(リクエスト毎に読まれるため再起動不要)。
{"allow":["192.168.0.0/16","geoserver.city.local","127.0.0.1"]}
許可エントリはホスト名・個別 IP・IPv4 CIDRのいずれかです(ホスト名一致はその名前への接続を全て許可)。管理ウィンドウの「その他」タブにある データ取得プロキシ セクションから GUI で編集・保存もできます(ローカル版でのみ表示)。
公開環境(Pages/Workers/Cloud Run)には /api/fetch は存在せず、ブラウザから直接 fetch する構成のため本対策の対象外です。
ページ内スクリプトの境界
- 資料モーダルの Markdown:リンク化は
http:/https:またはスキーム無し(相対パス)のみ。javascript:・data:等はリンク化せずテキストとして残します。 attr(出典)フィールドの HTML:許可リスト型サニタイズを適用。a・img・装飾タグ(b/i/em/u/br/span/small/sub/sup)のみを認め、URL はhttp(s):・相対のみ検証、on*等の属性は除去、リンクにはtarget="_blank" rel="noopener"を強制します。非許可タグは剥がしてテキストのみ残ります(描画時のみ適用・.kasc 上の値は変更しません)。runCode(AI 生成コード実行):sandbox="allow-scripts"の iframe(opaque origin)内で実行し、ブリッジ API はgetGoogleApiKey・saveStoragePlugin・saveDataFile・更新/停止系等の機密・高権限メソッドをブロックします。- レポート HTML:sandboxed iframe で描画します。
- プラグイン:仕様上
window.kasugaiApiへのフルアクセスを持つため、AI 生成プラグインの保存・公開には必ずコード全文を確認するダイアログを挟みます。ストレージプラグインは IndexedDB(ブラウザローカル)に閉じます。 - 外部エージェントの actions:破壊的ツール(
savePlugin/publishPlugin/deleteDataFile等)はフロント側の既存確認ダイアログで保護されます。
既知の制限・残課題
現時点で未対策と認識している項目です。信頼できない .kasc や不審な操作への注意をお願いします。
| 項目 | 状態 |
|---|---|
ローカルサーバーへのクロスサイトリクエスト(他サイトからの POST /api/shutdown 等) | Origin 検証は未実装。悪意あるページを開いたブラウザから 127.0.0.1 の API に単純リクエストが発射され得ます(プライベート帯への fetch 自体は上記許可リストで拒否済み) |
CSP・X-Content-Type-Options 等のセキュリティヘッダ | 未設定(blob import・srcdoc sandbox 等の機能と整合させる設計が必要) |
| CDN(jsdelivr の Cesium 等)のサブリソース完全性(SRI) | 未適用 |
自己更新(install_update)の署名・ハッシュ検証 | 未実装(配布元は GitHub の固定 URL のみ) |
POST /api/auth のレート制限 | 未実装 |
外部プロジェクトの @parent 配信 | .kasc 登録時に親フォルダ全体が HTTP 配信される設計。共有 DATA スコープの仕様ですが、登録時に配信範囲を確認してください |