はじめに
kintoneの無料のプラグインを入れる前に、「データを外に送っていないか」を確かめたいことがあります。情シスの立場だと、聞かれたときに根拠を持って答えたいところです。
手早いのは、開発者ツールで通信先のドメインを見ることです。ところが検証環境で試すと、それだけでは見落とす送り方がありました。
確かめた手順を、筆者のプラグインのzipを例に並べます。
結果
| 確かめること | 見る場所 |
|---|---|
| 1. 外部のJavaScriptを読み込んでいないか | zipの中の manifest.json
|
| 2. コードに通信の処理がないか | JavaScriptの中の fetch・XMLHttpRequest・kintone.proxy など |
| 3. kintone経由で外部に送っていないか | 開発者ツールの proxy/call.json の本文 |
| 4. 更新のzipが同じ鍵で作られたか | プラグインID |
見落としやすいのは3でした。送り先が外部でも、ブラウザから見える通信先は自分のcybozu.comです。
検証環境
- kintone(2026年11月7日時点)、kintoneシステム管理者のユーザー、Google Chrome
- 調べたzip:筆者の「台帳屋 棚卸し・変更監視パック」1.7.3
- zipの展開と検索は、Linuxの
unzipとgrepで実行
1. zipを2回展開して、manifest.json を見る
プラグインのzipを展開すると、次の3つが出てきます。
contents.zip
PUBKEY
SIGNATURE
本体は contents.zip のほうです。これをもう一度展開すると、manifest.json と js・css・html・画像が出てきます。Windowsなら、エクスプローラーの[すべて展開]で同じことができます。
manifest.json の desktop・mobile・config にある js と css には、zipの中のファイルのほかにURLも書けます。URLが書いてあれば、そのファイルは読み込むたびに外から取ってきます。zipを見ても中身は分かりません。
"desktop": {
"js": ["js/license.js", "js/refs.js", "js/fieldrefs.js", "js/xlsx.js", "js/desktop.js"],
"css": ["css/desktop.css"]
},
調べたzipは、すべてzipの中のファイルでした。
2. JavaScriptの中で、通信の処理を探す
unzip -q plugin.zip -d p1 && unzip -q p1/contents.zip -d p2
# 通信の処理
grep -rnE "fetch\(|XMLHttpRequest|kintone\.(plugin\.app\.)?proxy|sendBeacon|WebSocket" p2
# URL
grep -rnoE "https?://[^\"' )]+" p2
通信の処理は0件でした(kintoneのREST APIは kintone.api で呼んでいます)。URLは21か所出てきましたが、どれも通信ではありません。
| URL | 数 | 何か |
|---|---|---|
http://schemas.openxmlformats.org/... など |
16 | Excelのファイルの中に書く決まった文字列(XMLの名前空間) |
https://daichoya.github.io/... |
2 |
manifest.json の製品ページ |
https://daichoya.github.io/...・https://docs.google.com/...
|
3 | 画面のリンク(押したときに開く) |
URLが見つかっても、すぐに「送っている」とは言えません。前後の行を読んで、何に使っているかを見ます。
3. kintone経由の送信は、cybozu.comへの通信に見える
kintone.proxy は、kintoneのサーバーを通して外部のAPIを呼ぶ関数です。検証環境のコンソールから、https://example.com/ に送ってみました。ブラウザに見えた通信は、自分のcybozu.comへの1件だけです。
POST https://(サブドメイン).cybozu.com/k/api/proxy/call.json
{"url":"https://example.com/","method":"GET","headers":{},"body":{}, ...}
送り先は、リクエストの本文に入っていました。
開発者ツールの[Network]で domain:*.cybozu.com を入れて Invert(反転)にすると、cybozu.com以外への通信だけを見られます。ただ、この通信はそこには出てきません。ドメインで絞った[Network]が空でも、安心はできないということです。
確かめるときは、プラグインを使う画面で一通り操作してから、[Network]を proxy/call.json で絞り込みます。出てきたら、Payload(ペイロード)のタブで url を見ます。
プラグインの設定に保存した値(APIキーなど)を付けて外部に送る kintone.plugin.app.proxy もあります。2の grep は、こちらも探しています。
ちなみに、台帳屋のプラグインを入れた検証環境のアプリの一覧画面では、読み込まれたファイルと通信(184件)は、すべて自分のcybozu.com宛てでした。
4. 更新のzipは、プラグインIDで同じ鍵か分かる
PUBKEY は、zipに署名した鍵の公開鍵です。調べたzipでは、PUBKEY のSHA-256の先頭32文字を a〜p に置き換えた値が、kintoneのプラグインIDと一致しました。公式のドキュメントにはこの計算の説明が見つからなかったので、確かめた結果として書いておきます。
python3 -c "import hashlib;h=hashlib.sha256(open('p1/PUBKEY','rb').read()).hexdigest()[:32];print(''.join(chr(97+int(c,16)) for c in h))"
cokofaaeobgjffhicpaidfmbigdllokc
kintoneは、同じプラグインIDのファイルを読み込むと上書きします。更新のzipのIDが前と違えば、上書きではなく、別のプラグインとして入ります。入っているプラグインのIDは、コンソールで確かめられます。
(await kintone.api(kintone.api.url('/k/v1/plugins.json', true), 'GET', {})).plugins.map((p) => `${p.id} ${p.name} ${p.version}`);
※ コードを読んでも、すべての通信を見つけられるとは限りません(圧縮・難読化されたコード、外から読み込むJavaScript)。3の確認と合わせてください。
※ 確かめたのは、その版のzipです。更新のたびに確かめます。
※ kintoneシステム管理の[プラグイン]では、プラグインを使えるアプリを絞れます(プラグインの利用許可)。
さいごに
外部への通信を、ドメインだけで判断するのは危ないと分かりました。proxy/call.json の本文まで見て、やっと送り先が分かります。
筆者もkintoneのプラグインを作っています。台帳屋のプラグインは、どれもkintone(cybozu.com)以外とは通信しません。使うAPIの一覧は「導入前の確認事項」に載せています。