HMACを使ってiPaaSのWebhookを安全に利用
iPaaS環境のWebhookで外部からのデータを受け取るために、HMACを組み合わせた方法を紹介します。HMACを使うことで、送信元の真正性とデータの完全性を確保し、セキュリティ上の問題を回避できます。
▍iPaaSとは
iPaaS(integration Platform as a Service)は、別々のサービス同士を連携するサービスです。たとえば、Zapier、Make、Anyflow、Power Automate、IFTTTなどがあります。
データや操作を自動化でき、業務レベルでも個人レベルでも便利なものです。以下は使用例です。
タスク管理ツールとカレンダーを同期する
定期的にリマインドメールを送信する
メールの添付ファイルを自動でクラウドストレージに保存する
ツイートをチャットツールに転送する
▍iPaaSとWebhook
iPaaSでは、トリガー(きっかけ)をもとに、処理を実行します。多くのiPaaSはトリガーにWebhookを使えます。大まかに言えば、外部から呼び出せるURLを作れるということです。このURLにデータを送ると、処理が実行されます。
たとえば、自分のTwitterとInstagramアカウントに同じ投稿を送る仕組みを作り、トリガーをWebhookに設定したとします。この場合、そのWebhookのURLにデータ(投稿内容)を送ると、TwitterとInstagramに自動投稿されます。
このようにWebhookを使うと、任意のタイミングやデータでiPaaSの自動処理を実行できます。
▍Webhookのセキュリティ
Webhookを利用する際のセキュリティ上の問題として、WebhookのURLには誰でもデータを送れてしまうことが挙げられます。
なので、第三者からデータが送られたり、データが途中で改ざんされたりするリスクがあります。先ほどの例で言えば、自分のアカウントに意図しない内容が投稿される可能性があります。
HMAC(Hash-based Message Authentication Code)を利用すると、送信元が正しいこと、データが改ざんされていないことを確保できます。言い換えれば、送信元の真正性とデータの完全性の確保となります。
▍HMACを利用したデータの流れ
HMACでは、共通鍵(パスワードのようなもの)を使って、データからハッシュ値を作成します。共通鍵とデータが同じであれば、同じハッシュ値が作成されます。共通鍵かデータが少しでも異なれば、ハッシュ値は変わります。この特徴を利用して、身元確認と改ざん検知を行なっています。
流れを簡単に解説しておきます。なお、紙面の都合上、共通鍵とハッシュ値の長さを短くして書いています。
事前準備として、送信側と受信側には同じ共通鍵を用意しておきます。ハッシュ値の作成方法(SHA-256などのハッシュ関数)も同じものにしておきます。その後の流れは次のとおりです。
送信側で、共通鍵を使ってデータからハッシュ値を作成する
データとハッシュ値を送信する
受信側で、あらかじめ受信側が持っていた共通鍵を使って、送信されたデータからハッシュ値を作成する
受信側で作成したハッシュ値と、送信されたハッシュ値が同じであるかを確認する。もし一致しなければ、不正な共通鍵(≒不正な送信者)を使っているか、データが改ざんされている。
▍HMACを利用する際の留意点
HMACを利用する際には大きく2点考えることがあります。
① 使用するハッシュ関数
現在よく使われているのはSHA-256です。ただし、時代が進めば安全でなくなる(危殆化する)ので注意してください。CRYPTRECの暗号リストを見ておけば無難です。
② 共通鍵の取り扱い
鍵の長さとして、少なくともハッシュ関数の出力サイズと同等以上が推奨されます。SHA-256の場合は256ビット以上です。
また、第三者に漏れないよう適切に管理ください。
▍HMACの実装例
うちでは、送信側にGoogle Apps Script、受信側にiPaaSのWebhookを使用しています。iPaaSには、以前はZapier、現在はMakeを使っているので、それぞれ紹介します。
■ 送信側(Google Apps Scriptの場合)
ハッシュ値はhex(16進数)で表現することが一般的です。その手順を自作する必要があります。stack overflowの回答を流用したコードが以下です。
/**
*ハッシュ値を算出
*@param {string} data - データ
*@param {string} secret - 秘密鍵のキー
*@return {string} ハッシュ値
*/
function computeHash(data, secret) {
const byteSignature = Utilities.computeHmacSha256Signature(data, secret, Utilities.Charset.UTF_8);
return byteSignature.reduce((str, chr) => {
chr = (chr < 0 ? chr + 256 : chr).toString(16);
return str + (chr.length==1?'0':'') + chr;
}, '');
}
この関数を利用してハッシュ値を計算して、データとハッシュ値を送信しています。なお、ここではエラー処理は割愛して表示しています。
const secret = '秘密鍵のキー';
const data = '送信データ';
const hash = computeHash(data, secret);
const url = 'WebhookのURL';
const options = {
'method': 'post',
'payload': {
'text': data,
'hash': hash,
}
};
UrlFetchApp.fetch(url, options);
■受信側(Zapierの場合)
Zapの構成は以下です。1〜3がWebhook × HMACの箇所です。4はご自身が実行したい処理に合わせて変更ください。
まず、Webhookでデータを受信します。
次に、ハッシュ値を計算します。計算にはコードを使います。ここではJavaScriptを選んでいます。Input Dataには、送信側から送られてきたデータとハッシュ値を指定しています。
以下はコードです。送られてきたハッシュ値(hashReceived)と、この場で計算したハッシュ値(hashComputed)が一致するかを検証し、結果をsuccessfulに入れています。配列outputに連想配列を入れることで、この後の処理でsuccessfulを使えるようになります。
const crypto = require('crypto');
const SECRET = '秘密鍵のキー'; // 送信側と同じものを指定
const text = inputData.text;
const hashReceived = inputData.hashReceived;
let successful = false;
if(text && hashReceived) {
const hashComputed = crypto.createHmac('sha256', SECRET)
.update(text, 'utf8')
.digest('hex')
if(hashReceived == hashComputed) {
successful = true;
}
}
output = [{successful: successful}];
その次に、フィルターを設定しています。ハッシュ値が一致している場合のみ、後続の処理を行うように設定しています。
Zapierでの実装例は以上です。
■受信側(Makeの場合)
Makeの構成は以下です。Makeでは、フィルターで一通り実装できます。
以下はフィルターの設定です。送られてきたハッシュ値(1. hash)と、この場で計算したハッシュ値が一致する場合のみ、後続の処理を行います。
ハッシュ値の計算にはsha256関数を使っています。なお、第二引数はハッシュ値のエンコードです。既定がhexなので、ここでは指定を省略しています。
Makeでの実装例は以上です。
▍おわりに
iPaaSでWebhookを使う際には、第三者からのWebhook利用やデータの改ざんのリスクがあります。HMACを組み合わせることで、これらのリスクを低減できます。
一手間加えるだけで安全なデータの受け渡しを実現できるので、試してみてはいかがでしょうか。
私たちのデジタル技術活用のメモが次のマガジンにあります。よろしければ覗いてみてください!
この記事が気に入ったらサポートをしてみませんか?