NCMBで利用するアプリケーションキーとクライアントキーは、アプリ側の設定やACL(アクセス権限)が適切に設定されていれば、万一漏洩したとしても即座に不正利用につながるものではありません。
しかし、漏洩したことが分かればキーの再生成に加えて、アプリのビルドし直しやレビュー再提出と言った手間が発生します。
そこで、キーをファイルストアに保存しておき、それを随時取得する形の運用はできないか検討しました。100%必ず安全という訳ではありませんが、参照にしてください。
今回はWebやMonacaでの利用を想定しています。他の環境であればコンパイルするので、キーの漏洩は防げるかと思います。
ファイルストアのHTTPSファイル公開を利用する
NCMBのファイルストアでは、保存したファイルをHTTPS経由でアクセスできる機能があります。これを使って、認証キーなしでファイルストアからファイルをダウンロードできるようにします。設定は管理画面にあります。
ファイルを暗号化Zipでアップロードする
この時アップロードするファイルは暗号化Zipファイルとします。今回は config.zip
としています。内容は以下のようなJSONファイル config.json
を暗号化したものです。パスワードは ncmb
などとします。
{
"applicationKey": "YOUR_APPLICATION_KEY",
"clientKey": "YOUR_CLIENT_KEY"
}
この時のファイルURLは以下のようになるでしょう。
https://mbaas.api.nifcloud.com/2013-09-01/applications/uScDnX7D9IBrBMCU/publicFiles/config.zip
コードについて
ではこのファイルを読み込むのに必要なライブラリとしてzip.jsを使います。
<script src="https://unpkg.com/@zip.js/zip.js@2.6.62/dist/zip.min.js"></script>
<script src="https://unpkg.com/ncmb@3.1.5/ncmb.min.js"></script>
変数定義
先ほどのZip暗号化ファイルのURLと、パスワードを記述します。今回は平文で記述していますが、パスワードも暗号化するなりした方が良いでしょう。
const configZip = 'https://mbaas.api.nifcloud.com/2013-09-01/applications/uScDnX7D9IBrBMCU/publicFiles/config.zip';
const password = 'ncmb';
イベントハンドリング
Monacaであれば deviceready
、Webの場合は DOMContentLoaded
のイベントを使います。
const event = window.cordova ? 'deviceready' : 'DOMContentLoaded';
document.addEventListener(event, async (e) => {
// この中に記述
});
Zipファイルのダウンロード
Zipファイルはfetch関数でダウンロードします。
const res = await fetch(configZip);
const blob = await res.blob();
暗号化Zipファイルの中身を取り出す
zip.jsを使って暗号化Zipファイルの内容を読み取ります。
const config = JSON.parse(await decompress(blob));
decompress
関数の内容です。今回はconfig.jsonしか圧縮していないという決め打ちです。また、その内容はテキストファイルとして読み込みます。
const decompress = async (blob) => {
// Zip読み取り用リーダー
const reader = new zip.ZipReader(new zip.BlobReader(blob), { password });
// 1つ目のファイルが設定ファイル
const [entry] = await reader.getEntries();
// テキストでファイル内容を読み取り
return entry.getData(new zip.TextWriter());
}
NCMBの初期化
後はテキスト内容を使ってNCMBを初期化するだけです。
window.ncmb = new NCMB(config.applicationKey, config.clientKey);
全体の処理
今回の処理全体は以下のようになります。
// 設定ファイルのURL
const configZip = 'https://mbaas.api.nifcloud.com/2013-09-01/applications/uScDnX7D9IBrBMCU/publicFiles/config.zip';
// 暗号化Zipファイルのパスワード
const password = 'ncmb';
const event = window.cordova ? 'deviceready' : 'DOMContentLoaded';
document.addEventListener(event, async (e) => {
// Zipファイルを取得
const res = await fetch(configZip);
const blob = await res.blob();
// 設定ファイルの内容を読み込む
const config = JSON.parse(await decompress(blob));
// NCMBの初期化
window.ncmb = new NCMB(config.applicationKey, config.clientKey);
});
const decompress = async (blob) => {
// Zip読み取り用リーダー
const reader = new zip.ZipReader(new zip.BlobReader(blob), { password });
// 1つ目のファイルが設定ファイル
const [entry] = await reader.getEntries();
// テキストでファイル内容を読み取り
return entry.getData(new zip.TextWriter());
}
注意点
結局のところ、暗号化Zipファイルのパスワードが漏洩すると、Zipファイルを伸張できてしまいます。パスワードを暗号化したとしても、そのキーが漏洩したら…と堂々巡りにはなりそうです。
password
などの平易な変数名を使わないようにしたり、難読化する、パスワード文字列をJavaScript Obfuscator Toolで難読化するといった対処になるでしょう。Monacaアプリの場合はロジック暗号化プラグインを使って、ロジック全体を暗号化するのがお勧めです。
また、ファイルストアへのHTTPSアクセスもAPIアクセスにコールされるので注意してください。気になる場合には別なサーバーにアップしておく(CORS設定も必要そうです)のがお勧めです。
まとめ
ロジックが公開されてしまうJavaScriptでキーを隠蔽化するのには限度がありますが、ファイルストアに保存しておくことで、万一漏洩した際の差し替えも手軽になります。平文のファイルで保存するとあまり意味がないので、暗号化Zipファイルを使ってみました。
前述の通り、アプリの設定やACLを適切に行うのは基本として、その上でキーを隠蔽化したい場合に参考としてください。