実装

ドライブレコーダー — 映像は一フレームも触らずに

著者: makemind · 2026年4月9日

ドライブレコーダーは車内でいちばん機微なものを抱えている。ところが 映像以外は全部ありふれた運用データだ。 今日何回走ったか、カードがどれだけ残っているか、衝撃検知が敏感すぎて段差ごとに引っかかっていないか。車両管理者が毎日見るものだ。

これをアプリにする定番のやり方はひとつ。全部返す API を作り、映像のエンドポイントの前だけに権限検査を立てる。

その検査は 誰かが消せば消える。 急ぎのデプロイで、リファクタの途中で、テストを通すために。消しても残りは全部動くので、誰も気づかない。

道具一覧が表面だ

このサンプルのドラレコが差し出すもの、全部だ。

the dashcam offers: trips.list, camera.settings, camera.set_sensitivity
  trips.list — Trips recorded today, with duration, distance and impact counts
  camera.settings — Read the impact sensitivity and the card space
  camera.set_sensitivity — Set impact sensitivity, 1 (least) to 5 (most)

三つだ。映像を返す道具に鍵がかかっているのではなく、無い。

権限検査とこれは性質が違う。検査はコードで、コードは消せる。無い道具は 呼ぶ対象そのものが無い。 フロントがどれだけ雑に書かれても、トークンがどれだけ漏れても、一覧に無いものは呼ばれない。

クリップはハンドルだけが行き来する

では映像はどうなるのか。運行の行ごとにハンドルがひとつ付く。

clips referenced: clip:8841, clip:8842, clip:8843, clip:8844
TODAY · 4 TRIPS · 124.4 km — 運行4件、2件に衝撃表示、各行に clip ハンドル
TODAY · 4 TRIPS · 124.4 km — 運行4件、2件に衝撃表示、各行に clip ハンドル

clip:8842 はファイル名ではなく 不透明なハンドルだ。このサーバーはそのハンドルで何ひとつ開けない。車の前に立って見る権限のある人がそのクリップを探すときに使うものであり、同時に このサーバーが映像を読んだことがないという証拠だ。

ハンドルが行き来したことと中身が行き来したことは、まったく別の出来事だ。ログを見ればそれが区別できる — そのためにハンドルを残す。

映像は文章でも漏れる

ここでもう一歩進む。映像はファイルとしてだけ漏れるのではない。

「カメラが見たものの要約」は、文章に洗われた映像だ。 ナンバーを読んでテキストで渡せば、それは映像を渡していないことにはならない。歩行者が何人通ったかを数えて渡すのも同じだ。

だからサーバーが自分の出力を自分で塞ぐ。

/// Words this server must never emit. Footage leaks by being described as
/// much as by being served: a "summary of what the camera saw" is the video,
/// laundered through a sentence.
static const forbidden = [
  'plate', 'licence', 'license', 'face', 'pedestrian', 'frame',
  'thumbnail', 'preview', 'snapshot', 'image', 'footage of',
];

この一覧に引っかかれば応答を組み立てる途中で投げる。黙って消したりはしない — 消せば次にまた入る。

検証がサーバーの吐いた文字列を全部さらう。

no footage-describing vocabulary in anything the server returned

カメラが自分を切る

感度は 1 から 5 だ。画面のボタンひとつは意図的に 9 を要求する。

{ "type": "button", "label": "More sensitive",
  "onTap": { "type": "tool", "tool": "camera.set_sensitivity",
             "params": { "level": 9 } } }
asked for level 9 -> 5 of 5 ("sensitivity now 5")
impact sensitivity 5 of 5 · sensitivity now 5
impact sensitivity 5 of 5 · sensitivity now 5

カメラが切った。

// The camera clamps to its own range. A fleet console asking for 9
// gets 5, and is told so.
if (v < 1) v = 1;
if (v > 5) v = 5;

画面側で min/max をかけることもできた。それは 礼儀であって安全ではない。画面は JSON で、JSON はデプロイのたびに変わり、変わった画面が誤った値を送る日が来る。最後に受け止めるのは、いつでも凍っている側でなければならない。

そして切ったと伝える。黙って 5 にすれば、管理者は 9 に設定されていると思って過ごす。

このコンテンツは開発者以上が必要です

サインインしてプランをアップグレードすると続きを読めます。

プランを見る
Twitter