[{"data":1,"prerenderedAt":716},["ShallowReactive",2],{"content-/drawio-viewer-cdn-vs-local":3,"all-pages-for-dir":695,"related-/drawio-viewer-cdn-vs-local":696,"og-image-/drawio-viewer-cdn-vs-local":715},{"id":4,"title":5,"body":6,"category":681,"concepts":681,"description":682,"extension":683,"meta":684,"navigation":77,"ogImage":681,"path":685,"project_name":681,"published":686,"publishedAt":687,"seo":688,"source":681,"stem":689,"tags":690,"todo":681,"unpublished":686,"updatedAt":687,"__hash__":694},"pages/2025-12/2025-12-16/drawio-viewer-cdn-vs-local.md","Draw.io Viewer: CDN vs ローカルホストのセキュリティ比較",{"type":7,"value":8,"toc":655},"minimark",[9,13,17,26,103,107,112,119,125,147,152,163,169,173,178,183,194,198,203,211,216,219,223,275,278,349,352,359,362,388,391,394,408,411,415,441,444,460,463,466,501,504,534,538,542,545,564,569,577,581,599,602,645,651],[10,11,5],"h1",{"id":12},"drawio-viewer-cdn-vs-ローカルホストのセキュリティ比較",[14,15,16],"h2",{"id":16},"背景",[18,19,20,21,25],"p",{},"DrawioViewerコンポーネントで使用する ",[22,23,24],"code",{},"viewer-static.min.js","（約3.6MB）の読み込み方法として、以下の2つの選択肢がある。",[27,28,33],"pre",{"className":29,"code":30,"language":31,"meta":32,"style":32},"language-typescript shiki shiki-themes vitesse-light vitesse-light","// 方式1: CDN（外部サーバー）\nscript.src = 'https://viewer.diagrams.net/js/viewer-static.min.js'\n\n// 方式2: ローカルホスト（自サーバー）\nscript.src = '/js/viewer-static.min.js'\n","typescript","",[22,34,35,44,72,79,85],{"__ignoreMap":32},[36,37,40],"span",{"class":38,"line":39},"line",1,[36,41,43],{"class":42},"sxvE3","// 方式1: CDN（外部サーバー）\n",[36,45,47,51,55,58,61,65,69],{"class":38,"line":46},2,[36,48,50],{"class":49},"s4oTP","script",[36,52,54],{"class":53},"shFtX",".",[36,56,57],{"class":49},"src",[36,59,60],{"class":53}," =",[36,62,64],{"class":63},"sMJiu"," '",[36,66,68],{"class":67},"sdGka","https://viewer.diagrams.net/js/viewer-static.min.js",[36,70,71],{"class":63},"'\n",[36,73,75],{"class":38,"line":74},3,[36,76,78],{"emptyLinePlaceholder":77},true,"\n",[36,80,82],{"class":38,"line":81},4,[36,83,84],{"class":42},"// 方式2: ローカルホスト（自サーバー）\n",[36,86,88,90,92,94,96,98,101],{"class":38,"line":87},5,[36,89,50],{"class":49},[36,91,54],{"class":53},[36,93,57],{"class":49},[36,95,60],{"class":53},[36,97,64],{"class":63},[36,99,100],{"class":67},"/js/viewer-static.min.js",[36,102,71],{"class":63},[14,104,106],{"id":105},"cdn方式のセキュリティリスク","CDN方式のセキュリティリスク",[108,109,111],"h3",{"id":110},"_1-サプライチェーン攻撃中低リスク","1. サプライチェーン攻撃（中〜低リスク）",[18,113,114,118],{},[115,116,117],"strong",{},"概要",": CDNサーバーが侵害された場合に、悪意のあるコードが配信される可能性がある。",[18,120,121,124],{},[115,122,123],{},"実際の事例",":",[126,127,128,135,141],"ul",{},[129,130,131,134],"li",{},[115,132,133],{},"2021年 ua-parser-js事件",": npmパッケージが乗っ取られ、暗号通貨マイナーが注入された",[129,136,137,140],{},[115,138,139],{},"2022年 Heroku/Travis CI事件",": OAuthトークンが盗まれ、npmパッケージが改ざんされた",[129,142,143,146],{},[115,144,145],{},"2024年 polyfill.io事件",": CDNが買収され、悪意のあるコードが配信された（最も関連性が高い）",[18,148,149,124],{},[115,150,151],{},"Draw.ioの場合のリスク評価",[126,153,154,157,160],{},[129,155,156],{},"Draw.ioはJGraph社が運営する信頼性の高いサービス",[129,158,159],{},"大企業でも採用されており、セキュリティ意識は高い",[129,161,162],{},"ただし「絶対に安全」とは言えない",[18,164,165,168],{},[115,166,167],{},"影響",": 侵害された場合に、ページを閲覧したユーザーのブラウザで任意のJavaScriptが実行される可能性がある（XSS相当）",[108,170,172],{"id":171},"_2-cdnダウン時の可用性リスク低リスク","2. CDNダウン時の可用性リスク（低リスク）",[18,174,175,177],{},[115,176,117],{},": CDNがダウンした場合、図が表示されなくなる。",[18,179,180,124],{},[115,181,182],{},"Draw.ioの場合",[126,184,185,188,191],{},[129,186,187],{},"diagrams.netは高可用性インフラを使用",[129,189,190],{},"ダウン時は図が表示されないだけで、サイト全体は動く",[129,192,193],{},"実用上ほぼ問題にならない",[108,195,197],{"id":196},"_3-cspcontent-security-policyの緩和低リスク","3. CSP（Content Security Policy）の緩和（低リスク）",[18,199,200,202],{},[115,201,117],{},": 外部スクリプトを許可するため、CSPヘッダーを緩和する必要がある。",[27,204,209],{"className":205,"code":207,"language":208},[206],"language-text","# CDN使用時に必要なCSP\nscript-src 'self' https://viewer.diagrams.net;\n","text",[22,210,207],{"__ignoreMap":32},[18,212,213,215],{},[115,214,167],{},": CSPが緩くなることで、他の攻撃ベクトルが増える可能性。ただし、特定ドメインのみ許可するので影響は限定的。",[14,217,218],{"id":218},"リスクの現実的な評価",[108,220,222],{"id":221},"このサイトmdx-playgroundの場合","このサイト（mdx-playground）の場合",[224,225,226,239],"table",{},[227,228,229],"thead",{},[230,231,232,236],"tr",{},[233,234,235],"th",{},"要素",[233,237,238],{},"評価",[240,241,242,251,259,267],"tbody",{},[230,243,244,248],{},[245,246,247],"td",{},"サイトの性質",[245,249,250],{},"個人ブログ/技術メモ",[230,252,253,256],{},[245,254,255],{},"機密情報の有無",[245,257,258],{},"なし（認証なし、決済なし）",[230,260,261,264],{},[245,262,263],{},"ユーザー数",[245,265,266],{},"少数",[230,268,269,272],{},[245,270,271],{},"攻撃対象としての魅力",[245,273,274],{},"低い",[108,276,277],{"id":277},"リスク比較表",[224,279,280,296],{},[227,281,282],{},[230,283,284,287,290,293],{},[233,285,286],{},"リスク",[233,288,289],{},"CDN",[233,291,292],{},"ローカル",[233,294,295],{},"備考",[240,297,298,312,324,337],{},[230,299,300,303,306,309],{},[245,301,302],{},"サプライチェーン攻撃",[245,304,305],{},"△",[245,307,308],{},"◎",[245,310,311],{},"CDNは外部依存",[230,313,314,317,319,321],{},[245,315,316],{},"更新漏れによる脆弱性",[245,318,308],{},[245,320,305],{},[245,322,323],{},"ローカルは手動更新",[230,325,326,329,332,334],{},[245,327,328],{},"可用性",[245,330,331],{},"○",[245,333,308],{},[245,335,336],{},"CDNも十分安定",[230,338,339,342,344,346],{},[245,340,341],{},"管理コスト",[245,343,308],{},[245,345,305],{},[245,347,348],{},"ローカルは更新作業必要",[14,350,351],{"id":351},"結論と推奨",[108,353,355,356],{"id":354},"このサイトの場合-cdn方式で十分","このサイトの場合: ",[115,357,358],{},"CDN方式で十分",[18,360,361],{},"理由:",[363,364,365,371,377,383],"ol",{},[129,366,367,370],{},[115,368,369],{},"リスクが低い",": 個人ブログで機密情報なし、攻撃対象として魅力がない",[129,372,373,376],{},[115,374,375],{},"Draw.ioの信頼性",": 大手企業でも採用されている信頼性の高いサービス",[129,378,379,382],{},[115,380,381],{},"polyfill.io事件との違い",": polyfill.ioは買収されたが、Draw.ioはJGraph社が継続運営",[129,384,385,387],{},[115,386,341],{},": ローカルホストは更新忘れのリスクがある",[108,389,390],{"id":390},"ローカルホストが推奨されるケース",[18,392,393],{},"以下の場合はローカルホストを検討:",[126,395,396,399,402,405],{},[129,397,398],{},"金融・医療など機密性の高いサイト",[129,400,401],{},"認証情報を扱うサイト",[129,403,404],{},"企業のセキュリティポリシーで外部スクリプト禁止の場合",[129,406,407],{},"オフライン環境での動作が必要な場合",[14,409,410],{"id":410},"実装方法",[108,412,414],{"id":413},"cdn方式に変更する場合","CDN方式に変更する場合",[27,416,418],{"className":29,"code":417,"language":31,"meta":32,"style":32},"// DrawioViewer.vue の loadViewerScript 関数内\nscript.src = 'https://viewer.diagrams.net/js/viewer-static.min.js'\n",[22,419,420,425],{"__ignoreMap":32},[36,421,422],{"class":38,"line":39},[36,423,424],{"class":42},"// DrawioViewer.vue の loadViewerScript 関数内\n",[36,426,427,429,431,433,435,437,439],{"class":38,"line":46},[36,428,50],{"class":49},[36,430,54],{"class":53},[36,432,57],{"class":49},[36,434,60],{"class":53},[36,436,64],{"class":63},[36,438,68],{"class":67},[36,440,71],{"class":63},[18,442,443],{},"ローカルファイルは削除:",[27,445,449],{"className":446,"code":447,"language":448,"meta":32,"style":32},"language-bash shiki shiki-themes vitesse-light vitesse-light","rm apps/web/public/js/viewer-static.min.js\n","bash",[22,450,451],{"__ignoreMap":32},[36,452,453,457],{"class":38,"line":39},[36,454,456],{"class":455},"senZ8","rm",[36,458,459],{"class":67}," apps/web/public/js/viewer-static.min.js\n",[108,461,462],{"id":462},"ローカル方式を維持する場合",[18,464,465],{},"ファイルをgitにコミット:",[27,467,469],{"className":446,"code":468,"language":448,"meta":32,"style":32},"git add apps/web/public/js/viewer-static.min.js\ngit commit -m \"chore: add viewer-static.min.js for draw.io support\"\n",[22,470,471,481],{"__ignoreMap":32},[36,472,473,476,479],{"class":38,"line":39},[36,474,475],{"class":455},"git",[36,477,478],{"class":67}," add",[36,480,459],{"class":67},[36,482,483,485,488,492,495,498],{"class":38,"line":46},[36,484,475],{"class":455},[36,486,487],{"class":67}," commit",[36,489,491],{"class":490},"snbK4"," -m",[36,493,494],{"class":63}," \"",[36,496,497],{"class":67},"chore: add viewer-static.min.js for draw.io support",[36,499,500],{"class":63},"\"\n",[18,502,503],{},"定期的な更新（推奨: 3-6ヶ月ごと）:",[27,505,507],{"className":446,"code":506,"language":448,"meta":32,"style":32},"curl -L \"https://viewer.diagrams.net/js/viewer-static.min.js\" \\\n  -o apps/web/public/js/viewer-static.min.js\n",[22,508,509,527],{"__ignoreMap":32},[36,510,511,514,517,519,521,524],{"class":38,"line":39},[36,512,513],{"class":455},"curl",[36,515,516],{"class":490}," -L",[36,518,494],{"class":63},[36,520,68],{"class":67},[36,522,523],{"class":63},"\"",[36,525,526],{"class":490}," \\\n",[36,528,529,532],{"class":38,"line":46},[36,530,531],{"class":490},"  -o",[36,533,459],{"class":67},[14,535,537],{"id":536},"参考-サプライチェーン攻撃の事例","参考: サプライチェーン攻撃の事例",[108,539,541],{"id":540},"polyfillio事件2024年","polyfill.io事件（2024年）",[18,543,544],{},"最も関連性の高い事例。",[126,546,547,553,558],{},[129,548,549,552],{},[115,550,551],{},"経緯",": polyfill.ioドメインが中国企業に買収された",[129,554,555,557],{},[115,556,167],{},": CDNから悪意のあるコードが配信され、10万以上のサイトが影響",[129,559,560,563],{},[115,561,562],{},"対策",": Cloudflare/Fastlyが代替CDNを提供、多くのサイトがローカルホストに移行",[18,565,566,124],{},[115,567,568],{},"Draw.ioとの違い",[126,570,571,574],{},[129,572,573],{},"polyfill.ioは個人プロジェクトから始まり、運営が不安定だった",[129,575,576],{},"Draw.ioはJGraph社が商用サービスとして運営、買収リスクは相対的に低い",[108,578,580],{"id":579},"ua-parser-js事件2021年","ua-parser-js事件（2021年）",[126,582,583,588,593],{},[129,584,585,587],{},[115,586,551],{},": npmアカウントが乗っ取られ、暗号通貨マイナーが注入された",[129,589,590,592],{},[115,591,167],{},": 週間800万ダウンロードのパッケージが数時間汚染された",[129,594,595,598],{},[115,596,597],{},"教訓",": 人気パッケージでも信頼しすぎてはいけない",[14,600,601],{"id":601},"まとめ",[224,603,604,617],{},[227,605,606],{},[230,607,608,611,614],{},[233,609,610],{},"方式",[233,612,613],{},"推奨度",[233,615,616],{},"理由",[240,618,619,632],{},[230,620,621,626,629],{},[245,622,623,625],{},[115,624,289],{},"（このサイト向け）",[245,627,628],{},"⭐⭐⭐⭐⭐",[245,630,631],{},"リスク低、管理楽、Draw.io信頼性高",[230,633,634,639,642],{},[245,635,636,638],{},[115,637,292],{},"（高セキュリティサイト向け）",[245,640,641],{},"⭐⭐⭐⭐",[245,643,644],{},"外部依存なし、完全制御可能",[18,646,647,650],{},[115,648,649],{},"このサイトではCDN方式を推奨","。セキュリティと利便性のバランスが良い。",[652,653,654],"style",{},"html pre.shiki code .sxvE3, html code.shiki .sxvE3{--shiki-default:#A0ADA0;--shiki-dark:#A0ADA0}html pre.shiki code .s4oTP, html code.shiki .s4oTP{--shiki-default:#B07D48;--shiki-dark:#B07D48}html pre.shiki code .shFtX, html code.shiki .shFtX{--shiki-default:#999999;--shiki-dark:#999999}html pre.shiki code .sMJiu, html code.shiki .sMJiu{--shiki-default:#B5695977;--shiki-dark:#B5695977}html pre.shiki code .sdGka, html code.shiki .sdGka{--shiki-default:#B56959;--shiki-dark:#B56959}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .senZ8, html code.shiki .senZ8{--shiki-default:#59873A;--shiki-dark:#59873A}html pre.shiki code .snbK4, html code.shiki .snbK4{--shiki-default:#A65E2B;--shiki-dark:#A65E2B}",{"title":32,"searchDepth":46,"depth":46,"links":656},[657,658,663,667,672,676,680],{"id":16,"depth":46,"text":16},{"id":105,"depth":46,"text":106,"children":659},[660,661,662],{"id":110,"depth":74,"text":111},{"id":171,"depth":74,"text":172},{"id":196,"depth":74,"text":197},{"id":218,"depth":46,"text":218,"children":664},[665,666],{"id":221,"depth":74,"text":222},{"id":277,"depth":74,"text":277},{"id":351,"depth":46,"text":351,"children":668},[669,671],{"id":354,"depth":74,"text":670},"このサイトの場合: CDN方式で十分",{"id":390,"depth":74,"text":390},{"id":410,"depth":46,"text":410,"children":673},[674,675],{"id":413,"depth":74,"text":414},{"id":462,"depth":74,"text":462},{"id":536,"depth":46,"text":537,"children":677},[678,679],{"id":540,"depth":74,"text":541},{"id":579,"depth":74,"text":580},{"id":601,"depth":46,"text":601},null,"viewer-static.min.jsをCDNから読み込むか、ローカルにホストするかの選択について、セキュリティリスクと実用性を詳細に比較","md",{},"/drawio-viewer-cdn-vs-local",false,"2025-12-16T00:00:00.000Z",{"title":5,"description":682},"2025-12/2025-12-16/drawio-viewer-cdn-vs-local",[691,692,289,693],"security","draw.io","supply-chain","6_l8OLhMZJSrgCFfzBQhPRsvLcOUjd8GCEw0wDhP9EQ",[],[697,701,704,708,712],{"title":698,"path":699,"publishedAt":700},"Draw.io動的埋め込み：セキュリティレビュー","/drawio-embedding-security-review","2025-11-19T00:00:00.000Z",{"title":702,"path":703,"publishedAt":700},"セキュリティ改善実装レポート","/security-improvements-implementation",{"title":705,"path":706,"publishedAt":707},"CT Logとbot対策：AI検索で参照されたいならBot Fight Modeを入れてはいけない","/ct-log-bot-and-ai-search","2026-05-06T00:00:00.000Z",{"title":709,"path":710,"publishedAt":711},"GitHub 158リポを棚卸し、Dependabot・Push Protection・Secret Scanningの現状把握から明日のTODOへ","/github-security-audit-prep","2026-05-02T00:00:00.000Z",{"title":713,"path":714,"publishedAt":711},"マネーフォワードGitHub流出を受けて、ひとり開発の秘密管理を棚卸しした","/moneyforward-leak-lessons","https://log.eurekapu.com/og/blog/drawio-viewer-cdn-vs-local.png?v=2025-12-16T00%3A00%3A00.000Z&title=Draw.io%20Viewer%3A%20CDN%20vs%20%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%83%9B%E3%82%B9%E3%83%88%E3%81%AE%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E6%AF%94%E8%BC%83&author=Kei%20Komatsu&sig=31e5222e7dded3fa",1785654962470]