はじめに
あと1年ほどでサービスが終了してしまうLINE Pay。
今回焦点を当てたのは、LINE Pay APIの認証方法で使われている「HMAC-SHA256」ハッシュ作成方法です。
この方法を参考にした認証方法をサービスに組み込んだのですが、Google Apps Scriptから利用するときは工夫が必要でしたので、記事を書くことにします。
LINE Pay APIで利用されているハッシュの作り方
Signature = Base64(HMAC-SHA256(Your ChannelSecret, (Your ChannelSecret + URL Path + Query String + nonce)))
※ Query String : ?を除いたクエリ文字列(例 : Name1=Value1&Name2=Value2...)
サービス用にカスタマイズしたハッシュの作り方
Signature = Base64(HMAC-SHA256(Your ChannelSecret, (Your ChannelSecret + Request Body + nonce)))
実装したロジック
$ChannelSecretKey = 'secret_key';
$request = ['テスト'];
$nonce = (string)microtime(TRUE);
$payload = json_encode($request, JSON_UNESCAPED_UNICODE);
$message = $ChannelSecretKey.$payload.$nonce;
$signature = base64_encode(hash_hmac('sha256', $message, $ChannelSecretKey , true));
const request = [
'テスト'
]
const payload = JSON.stringify(request)
const nonce = Date.now().toString()
const data = SECRET_KEY + payload + nonce
const rawSignature = Utilities.computeHmacSha256Signature(data, SECRET_KEY)
const signature = Utilities.base64Encode(rawSignature)
Logger.log('Generated Signature: ' + signature)
沼ったポイント
Google Apps Script(クライアント)からPHP(サーバー)のAPIを呼び出すことを目標としているのですが、
何度Google Apps Scriptでシグネチャを作成しても、PHP側で作成したシグネチャと一致しない。
という問題に直面しました。
「ChatGPT」に質問をしても「問題ない」との一点張りでなかなか解決に向かいませんでした。
判明した原因
$request = ['テスト'];
としていましたが、
$request = ['test'];
にしたら、どうなるのだろうか。
と思い試したところ、シグネチャがPHPクライアントと一致することが確認できました。
つまり実装自体は間違っていなかったことになります。
つまりGoogle Apps Scriptクライアントの挙動が日本語の有無に左右されていたことになります。
今回PHPで作成するシグネチャとGoogle Apps Scriptで作成するシグネチャが一致しない原因として、
内部エンコーディングが一致していないことが原因でした。
PHPは内部エンコーディングがUTF-8だった。
Google Apps Scriptは内部エンコーディングがUTF-8ではなかった。
上記の理由から、シグネチャの作成ロジックを見直すことになりました。
改良版の作成
const request = [
'テスト'
]
const payload = JSON.stringify(request)
const nonce = Date.now().toString()
const data = SECRET_KEY + payload + nonce
// UTF-8バイト配列に変換
const utf8Data = Utilities.newBlob(data).getBytes() // 追加
const utf8Key = Utilities.newBlob(SECRET_KEY).getBytes() // 追加
const rawSignature = Utilities.computeHmacSha256Signature(utf8Data, utf8Key) // 修正
const signature = Utilities.base64Encode(rawSignature)
Logger.log('Generated Signature: ' + signature)
最後に
Utilities.computeHmacSha256Signature
とUtilities.base64Encode
が悪いのだと思い、ライブラリの変更ばかりに目が行っていましたが、理由は単純なものでした。