Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
見た目は同じなのに検索でヒットしない:ファイルアップロード実装の落とし穴と設計を考える
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
wabi
May 09, 2026
380
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
見た目は同じなのに検索でヒットしない:ファイルアップロード実装の落とし穴と設計を考える
wabi
May 09, 2026
More Decks by wabi
See All by wabi
俺の勉強会運営考察 集客と場づくりがうまくいった要因を振り返る
wabi_1318
0
280
AIにAIのplanをレビューをさせるSKILLを作った
wabi_1318
0
1k
chrome-devtools-mcp.pdf
wabi_1318
0
120
2025年を振り返っていけ
wabi_1318
0
49
俺の勉強会を振り返る 2025
wabi_1318
2
960
生成AI×社会課題ハッカソン2冠で見えた AI時代にエンジニアが伸びるための姿勢
wabi_1318
1
1.9k
名古屋で「俺の勉強会」を始めた話 〜初開催から 4 ヶ月で LT 枠が即日埋まる(自称)人気勉強会になった理由をみんなで考えたい〜
wabi_1318
0
50
ハッカソンで2冠してきた話〜AI時代に取るべき姿勢が分かったかもしれない件について〜
wabi_1318
3
390
「俺の勉強会」がはじまるよ!
wabi_1318
1
1.9k
Featured
See All Featured
Faster Mobile Websites
deanohume
310
32k
Design in an AI World
tapps
1
260
The AI Search Optimization Roadmap by Aleyda Solis
aleyda
1
6k
Crafting Experiences
bethany
1
220
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
Discover your Explorer Soul
emna__ayadi
2
1.2k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
180
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
360
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.7k
Neural Spatial Audio Processing for Sound Field Analysis and Control
skoyamalab
0
370
The agentic SEO stack - context over prompts
schlessera
0
850
Transcript
⾒た⽬は同じなのに検索でヒットしない ファイルアップロード実装の落とし⽳と設計を考える wabi フロントエンドカンファレンス名古屋 2026
⽬次 1. 何が起きたか(再現する) 2. なぜ起きたか(⽂字列の中⾝を⾒る) 3. 誰がやるべきか(ブラウザ‧ライブラリ任せにできない) 4. どこで揃えるか(境界で正規化する) 2
⽬次 1. 何が起きたか(再現する) 2. なぜ起きたか(⽂字列の中⾝を⾒る) 3. 誰がやるべきか(ブラウザ‧ライブラリ任せにできない) 4. どこで揃えるか(境界で正規化する) 3
きっかけ ファイルアップロード機能を扱った際、 macOS からアップロードされたはずのファイル名が、検索でヒットしない というバグに遭遇した 1. 何が起きたか(再現する) 4
再現環境 項⽬ 条件 OS / ファイルシステム ブラウザ Chrome 147 /
Safari 26.4 / Firefox 150 デモアプリ Node.js v22.15.0 1. 何が起きたか(再現する) 5 macOS 26.4.1(25E253) / APFS
再現⼿順 1. Finder で ファイルを作成‧「プロフィール画像 .jpg」にリネーム 1. 何が起きたか(再現する) 6 ※
デモアプリを使用
2. Web アプリにファイルをアップロード Node.js サーバーにファイル名が保存される 1. 何が起きたか(再現する) 7
3. ファイル名検索欄に 「プロフィール画像 .jpg」 をキーボードで ⼿⼊⼒して検索 0 件 ヒット 1.
何が起きたか(再現する) 8
⽬次 1. 何が起きたか(再現する) 2. なぜ起きたか(⽂字列の中⾝を⾒る) 3. 誰がやるべきか(ブラウザ‧ライブラリ任せにできない) 4. どこで揃えるか(境界で正規化する) 9
コンソールで値を確認してみる 2. なぜ起きたか(⽂字列の中⾝を⾒る) 10
表⽰は同じでも、⽂字列⽐較は false console.logでは、アップ ロードしたファイル名と検索 ⽂字列の「プロフィール画 像.jpg」は同じに⾒える。 厳密等価演算⼦で⽐較すると false になる 2.
なぜ起きたか(⽂字列の中⾝を⾒る) 11
1⽂字ずつコードポイント (16進数) で⾒る 2. なぜ起きたか(⽂字列の中⾝を⾒る) 12
コードポイント上では違った! アップロードで保存された 「プロフィール画像.jpg」 コードポイントの数: 13個 30d5 , 309a , 30ed
, ... 検索フォームに⼊⼒した 「プロフィール画像.jpg」 コードポイントの数:12個 30d7 , 30ed , 30d5 , ... 2. なぜ起きたか(⽂字列の中⾝を⾒る) 13
Unicode では同じ⽂字を複数の形で表せる 表現 コードポイント 正規化形式 プ = 合成済みの1⽂字 U+30D7 NFC
フ + ゚ = 分解済みの2⽂字 U+30D5 + U+309A NFD 先ほどの結果から、 Finderで作成した「プロフィール画像.jpg」は NFD キーボード⼊⼒で作成した「プロフィール画像.jpg」は NFC であることがわかった 2. なぜ起きたか(⽂字列の中⾝を⾒る) 14
バグの経路を整理 NFD ‧NFC の⽂字列が、正規化されることなくそのまま検索処理まで届いていた 2. なぜ起きたか(⽂字列の中⾝を⾒る) 15
⽬次 1. 何が起きたか(再現する) 2. なぜ起きたか(⽂字列の中⾝を⾒る) 3. 誰がやるべきか(ブラウザ‧ライブラリ任せにできない) 4. どこで揃えるか(境界で正規化する) 16
正規化形式の統⼀はブラウザ任せにできない String.prototype.normalize() メソッドを使⽤し、正規化形式を確認 3. 誰がやるべきか(ブラウザ‧ライブラリ任せにできない) 17
正規化形式の統⼀はブラウザ任せにできない 経路ごとに JS へ渡る「プロフィール画像.jpg」の正規化形式が異なっていた ⼊⼝ 確認した値 結果 ファイルアップロ ード file.name
の値 NFD 検索フォーム キーボード⼊⼒後の searchInput.value NFC Finder からコピ ー&ペースト 貼り付け後の searchInput.value Chrome/Firefox: NFD Safari: NFC 3. 誰がやるべきか(ブラウザ‧ライブラリ任せにできない) 18
正規化形式の統⼀はブラウザ任せにできない 標準で⼀律に吸収される問題ではない 資料 内容 Chromium 41291096 NFD のファイル名がアップロード時に NFC に正規化され
ないバグ報告(未クローズ) Mozilla 695995 Mac からアップロードされたファイル名が分解形のまま 送信される(未クローズ) WebKit 91817 ファイル名を正規化すべきではないのでは、という議論 (未クローズ) 3. 誰がやるべきか(ブラウザ‧ライブラリ任せにできない) 19
ライブラリ任せにもできない アップロード関連ライブラリを調査したが、正規化の保証は確認できなかった 調査対象 デフォルトで NFC 正規化 ファイル名関連 Issue react-dropzone v15.0.0
+ file-selector 2.1.x なし — Uppy 5.2.4 なし — FilePond 4.32.12 なし — Dropzone.js 6.0.0-beta.2 なし #1746, #1764 どの正規化形式に揃えるかは、アプリ側の設計判断になる 3. 誰がやるべきか(ブラウザ‧ライブラリ任せにできない) 20 File.name を扱うが、ファイル名の Unicode 正規化まで保証するとは限らない
⽬次 1. 何が起きたか(再現する) 2. なぜ起きたか(⽂字列の中⾝を⾒る) 3. 誰がやるべきか(ブラウザ‧ライブラリ任せにできない) 4. どこで揃えるか(境界で正規化する) 21
⼊⼒境界で⽂字列を検証‧正規化するよう設計する ブラウザ API から受け取った string を、そのまま⽐較‧検索‧参照に使わない。 セキュリティ⽂脈では「不正な⽂字エンコーディングは⼊⼒時にチェックする」という原則がある。 今回の NFC /
NFD は不正ではないが、⼊⼒時に揃えるという意味では同じ設計判断。 4. どこで揃えるか(境界で正規化する) 22
正規化済みの値だけを内部に流す 4. どこで揃えるか(境界で正規化する) 23 • 処理へ渡す前に必ず変換関数を通るような設計にする • 型で素の string と検索⽤の値を区別をつける
ファイルアップロードで受け取った⽂字列は 使う前に検証‧正規化する ファイル名などはただの⽂字列として⾒落としがち 実際にライブラリやプロダクト でも Issue になっている ⽐較‧検索‧参照の前に検証‧正規化することを意識しよう [1] Nextcloud
Text #7873: https://github.com/nextcloud/text/issues/7873 まとめ [1] 24
Thank you! wabi SWE @ 株式会社ココロザシ 俺の勉強会‧ フロントエンドカンファレンス名古屋 Organizer 25
参考⽂献 21 • https://developer.mozilla.org/ja/docs/Web/API/File • https://developer.mozilla.org/ja/docs/Web/JavaScript/ference/Global_Objects/String/codePointAt • http://developer.mozilla.org/ja/docs/Glossary/de_point • [改訂新版]プログラマのための文字コード技術入門
矢野啓介著 • https://qiita.com/ko1nksm/items/3a66197efd1c096a801f • https://issues.chromium.org/issues/41291096 • https://developer.mozilla.org/ja/docs/Web/JavaScript/ference/Global_Objects/String/normalize • 体系的に学ぶ 安全なWebアプリケーションの作り方 第2版 脆弱性まれる原理と対策の実践 徳丸 浩著 • https://w3c.github.io/FileAPI/#dfn-name • https://developer.mozilla.org/ja/docs/Web/API/File/bkitRelativePath • https://developer.mozilla.org/ja/docs/Web/API/File/me • https://wicg.github.io/entries-api/om-file-webkitrelativepath • https://github.com/react-dropzone/file-selector • https://github.com/react-dropzone/react-dropzone • https://github.com/transloadit/uppy • https://github.com/pqina/filepond • https://github.com/dropzone/dropzone • https://github.com/nextcloud/text/issues/7873 • Domain Modeling Made Functional Scott Wlaschin著 • https://qiita.com/uhyo/items/de4cb2085fdbdf484b83