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
350
3
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
270
AIにAIのplanをレビューをさせるSKILLを作った
wabi_1318
0
1k
chrome-devtools-mcp.pdf
wabi_1318
0
120
2025年を振り返っていけ
wabi_1318
0
43
俺の勉強会を振り返る 2025
wabi_1318
2
950
生成AI×社会課題ハッカソン2冠で見えた AI時代にエンジニアが伸びるための姿勢
wabi_1318
1
1.8k
名古屋で「俺の勉強会」を始めた話 〜初開催から 4 ヶ月で LT 枠が即日埋まる(自称)人気勉強会になった理由をみんなで考えたい〜
wabi_1318
0
48
ハッカソンで2冠してきた話〜AI時代に取るべき姿勢が分かったかもしれない件について〜
wabi_1318
3
380
「俺の勉強会」がはじまるよ!
wabi_1318
1
1.9k
Featured
See All Featured
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
62
44k
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
370
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.6k
The World Runs on Bad Software
bkeepers
PRO
72
12k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.5k
エンジニアに許された特別な時間の終わり
watany
107
250k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
55
3.4k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
950
The SEO Collaboration Effect
kristinabergwall1
1
490
Navigating the moral maze — ethical principles for Al-driven product design
skipperchong
2
400
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.2k
Building Flexible Design Systems
yeseniaperezcruz
330
40k
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