- RSS フィードを購読する
- 新着としてマーク
- 既読としてマーク
- ブックマーク
- 購読
- 印刷用ページ
- 不適切なコンテンツを報告
@Jo_o Salvador 氏のコメントもぜひご覧ください。HTTP 認証プロファイルを使用して HMAC 検証を実装する、ノーコードのプラットフォームネイティブアプローチが紹介されています。独自にスクリプトを記述する必要がない場合は、その必要はありません。この記事は、より高度なユースケースや、内部でどのように機能するかを理解したい場合に役立ちます。
HMAC 検証とは何ですか?
HMAC 検証の仕組み
- API: Webhook を呼び出すサードパーティ API。
- アプリ: Webhook エンドポイントを含むお使いのアプリケーション。
- 秘密鍵 (シークレット): API とアプリの両方が持つ共有秘密鍵であり、他の全員には秘密にされています。API は通常、この秘密鍵 (通常は文字列値) を提供します。
- メッセージ: 検証が必要な Webhook エンドポイントに送信されるペイロード。
- 署名: API とアプリの両方が、秘密鍵と API が指定するプロセスを使用して生成する文字列値。
- API は、API が指定する秘密鍵とプロセスを使用して署名を生成します。
- API は署名とメッセージをアプリの Webhook エンドポイントに送信します。
- アプリは、API が指定する秘密鍵とプロセスを使用して署名を生成します。
- アプリは、API 署名をアプリが生成した署名と比較します。
- 署名が一致する場合、メッセージは API からのものであり、変更されていないことが検証されます。
- 署名が次のいずれかと一致しない場合:
- メッセージは API からのものとして信頼しないでください。
- メッセージは、中間者攻撃によって変更された可能性があります。
- アプリの署名生成コードを台無しにしてしまった可能性があります。
Replicate AI の HMAC 実装
Webhook の構造
webhook-id:msg_1234567890abcdef
webhook-timestamp:1640995200
webhook-signature: v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE= v1,bm9ldHUjKzFob2VudXRob2VodWUzMjRvdWVvdW9ldQo=
- webhook-id: この特定の Webhook 配信の一意の識別子。
- webhook-timestamp: Webhook が送信された日時を示す Unix タイムスタンプ。
- webhook-signature: バージョンプレフィックスを持つ署名のスペース区切りリスト。
署名の生成
const signedContent = `${webhook_id}.${webhook_timestamp}.${body}`;
whsec_C2FVsBQIhrscChlQIMV+b5sSYspob7oDのような秘密鍵も提供されます。奇妙なことに、実際の秘密鍵は先頭のwhsec_を除いた部分であり、これは少し混乱を招きました。署名を生成するために、Replicate AI は秘密鍵、署名済みコンテンツ、および SHA-256 アルゴリズムを使用します。
ServiceNow HMAC 検証の実装
- HTTP ヘッダーを抽出します。
- メッセージコンテンツを取得します。
- 署名済みコンテンツを構築します。
- 署名を生成します。
var ReplicateAI = Class.create();
ReplicateAI.prototype = {
initialize: function () {
this.token = '';
},
getWebhookSigningSecret: function () {
return gs.getProperty('x_snc_cctcg_photo.replicate_ai_secret_key');
},
updateWebhookSigningSecret: function () {
this.getAPIToken();
const request = new sn_ws.RESTMessageV2();
request.setEndpoint('https://api.replicate.com/v1/webhooks/default/secret');
request.setHttpMethod('GET');
request.setRequestHeader('Authorization', `Bearer ${this.token}`);
request.setRequestHeader('Content-Type', "application/json");
const resp = JSON.parse(request.execute().getBody());
gs.setProperty('x_snc_cctcg_photo.replicate_ai_secret_key', resp.key);
},
isWebhookValid: function (request, body) {
const secret = this.getWebhookSigningSecret().split('_')[1]; // Remove whsec_ prefix
const signatures = request.getHeader('webhook-signature').split(' ');
const webhookId = request.getHeader('webhook-id');
const timestamp = request.getHeader('webhook-timestamp');
return signatures.some((signature) => {
let signatureBase64 = signature.split(',')[1]; // Remove version prefix (v1,)
const signedContent = `${webhookId}.${timestamp}.${body}`;
const mac = new CertificateEncryption();
const generatedSignature = mac.generateMac(secret, 'HmacSHA256', signedContent);
return signatureBase64 == generatedSignature;
});
},
getAPIToken: function () {
if (this.token) {
return;
}
const credentialAlias = 'your_credential_alias_sys_id';
const provider = new sn_cc.StandardCredentialsProvider();
const cred = provider.getCredentialByAliasID(credentialAlias);
this.token = cred.getAttribute('api_key');
},
type: 'ReplicateAI'
};
isWebhookValid関数 (上記22行目) はプロセスのエントリポイントであり、Scripted REST API 内から実行されます (下の 8 行目)。
(function process(request, response) {
const log = new Log();
const replicate = new ReplicateAI();
const resp = request.body.data;
try {
// Critical: Use JSON.stringify to ensure exact body representation
if (!replicate.isWebhookValid(request, JSON.stringify(resp))) {
log.insert({
type: 'Error',
message: 'Unauthorized webhook attempt',
payload: resp,
});
response.setStatus(401);
return;
}
// Process validated webhook...
if (resp && resp.output && resp.output.length) {
// Handle successful AI processing
resp.output.forEach((generatedImage) => {
// Your business logic here
});
} else if (resp && resp.error) {
// Handle AI processing errors
log.insert({
type: 'Error',
message: 'AI processing failed',
payload: resp,
});
}
} catch (err) {
log.insert({
type: 'Error',
message: 'Webhook processing error',
payload: err.toString(),
});
response.setStatus(500);
}
})(request, response);
間違いと HMAC デバッグが厄介な理由
間違い #1: アルゴリズム名の混乱
// This is what I tried first (because that's what the Replicate docs said)
mac.generateMac(secret, 'SHA-256', signedContent);
// But ServiceNow wants this format
mac.generateMac(secret, 'HmacSHA256', signedContent);
SHA-256が実際に機能するかどうかは分かりません。しかし、この特定の関数の例にはHmacSHA256が記載されており、それが最終的に私にとっては機能しました。ただし、これらのアルゴリズムには注意が必要です。
間違い #2: 秘密鍵プレフィックスの問題
// I forgot to strip this for way too long
const secret = 'whsec_C2FVsBQIhrscChlQIMV+b5sSYspob7oD';
// You need to remove the whsec_ prefix
const secret = 'C2FVsBQIhrscChlQIMV+b5sSYspob7oD';
whsec_秘密鍵を取得するためにはこれを剥ぎ取る必要があったことです。署名を生成する際には、これらの些細な詳細が非常に重要です。秘密鍵のこれら 6 文字の違いは、劇的に異なる署名につながり、結果として得られる署名にはその理由を示すものは何もありません。
間違い #3: ボディコンテンツの処理
// Non-Strings will get silently converted to strings like [Object object]
const body = request.body.data;
// You need the exact string representation
const body = JSON.stringify(request.body.data);
間違い #4: Base64 エンコーディングの混乱
役に立つアドバイス
役に立つアドバイス #1: すべてをログに記録する
役に立つアドバイス #2: 最初に既知の値でテストする
役に立つアドバイス #3: 核心から取り組む
generateMac関数から開始し、そこから段階的に検証を進めることをお勧めします。既知の値でその関数をテストし、適切なアルゴリズムが使用され、正しい入力が正しい場所に設定されていることを確認してください。次に、入力を一度に 1 つずつより汎用的なものにします。これにより、どの値がエラーの原因となっているのかを特定しやすくなります。役に立つアドバイス #4: API の検証プロセスを書き出す
- ✓ Webhook ID、タイムスタンプ、本文をピリオドで連結する。
- ✓ 受け取ったとおりに生の本文を使用する。
- ✓ 秘密鍵から「whsec_」プレフィックスを取り除く。
- ✓ 署名からバージョンプレフィックスを削除する (「v1,」)。
- ✓ SHA-256を使用する。
役に立つアドバイス #5: AI に助けを求めることを恐れないでください
この記事は機械翻訳されております。最新は元となる記事をご覧ください: https://www.servicenow.com/community/developer-advocate-blog/hmac-validation-in-servicenow-securing-...。
免責事項: 一部の日本語は、翻訳ソフトウェアを使用してお客様の便宜のために翻訳されています。正確な翻訳をご提供できるよう相当な努力を払っておりますが、いかなる自動翻訳も人間の翻訳者に代わすることはなく、そのようなことは意図されておりません。翻訳は「現状のまま」提供されています。他言語への翻訳の的確性、信頼性または正確性については、明示または黙示を問わず、いかなる保証も行われません。翻訳ソフトには限界があるため、一部のコンテンツが正確に翻訳されていない場合があります。これらの資料の公用言語は英語です。翻訳の際に生じる相違または不一致は、コンプライアンスまたは履行の目的に関しては拘束力を有さず、法的効力はないものとします。
This article was machine translated and replicated from the original source: https://www.servicenow.com/community/developer-advocate-blog/hmac-validation-in-servicenow-securing-...。