使用 Cloudflare Worker 验证 HMAC 哈希
Verify HMAC Hash Using Cloudflare Workers
我正在尝试验证从 WebHook 收到的 HMAC 签名。 WebHook 的详细信息是 https://cloudconvert.com/api/v2/webhooks#webhooks-events
这表示 HMAC 是使用 hash_hmac (PHP) 生成的,并且是正文的 SHA256 散列 - 即 JSON。收到的示例是:
c4faebbfb4e81db293801604d0565cf9701d9e896cae588d73ddfef3671e97d7
这看起来像是小写的十六进制。
我正在尝试使用 Cloudflare Workers 来处理请求,但是我无法验证哈希。我的代码如下:
const encoder = new TextEncoder()
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
const contentType = request.headers.get('content-type') || ''
const signature = request.headers.get('CloudConvert-Signature')
let data
await S.put('HEADER', signature)
if (contentType.includes('application/json')) {
data = await request.json()
await S.put('EVENT', data.event)
await S.put('TAG', data.job.tag)
await S.put('JSON', JSON.stringify(data))
}
const key2 = await crypto.subtle.importKey(
'raw',
encoder.encode(CCSigningKey2),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
)
const signed2 = await crypto.subtle.sign(
'HMAC',
key2,
encoder.encode(JSON.stringify(data))
)
await S.put('V22', btoa(String.fromCharCode(...new Uint8Array(signed2))))
return new Response(null, {
status: 204,
headers: {
'Cache-Control': 'no-cache'
}
})
}
这将生成一个散列:
e52613e6ecebdf98bb085f04ca1f91bf9a5cf1dc085f89dcaa3e5fbf5ebf1b06
我试过使用 crypto.subtle.verify 方法,但没有用。
有人能看出代码有什么问题吗?或者是否已使用 Cloudflare Workers 成功完成此操作?
马克
我终于使用验证方法完成了这个工作(我之前尝试过验证方法,但没有成功)。主要问题似乎是使用 request.json() 包装在 JSON.stringify 中。将其更改为 request.text() 解决了该问题。然后我可以在验证签名后使用 JSON.parse 来访问数据。代码如下:
const encoder = new TextEncoder()
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
const signature = request.headers.get('CloudConvert-Signature')
const key = await crypto.subtle.importKey(
'raw',
encoder.encode(CCSigningKey2),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['verify']
)
const data = await request.text()
const verified = await crypto.subtle.verify(
'HMAC',
key,
hexStringToArrayBuffer(signature),
encoder.encode(data)
)
if (!verified) {
return new Response('Verification failed', {
status: 401,
headers: {
'Cache-Control': 'no-cache'
}
})
}
return new Response(null, {
status: 204,
headers: {
'Cache-Control': 'no-cache'
}
})
}
function hexStringToArrayBuffer(hexString) {
hexString = hexString.replace(/^0x/, '')
if (hexString.length % 2 != 0) {
return
}
if (hexString.match(/[G-Z\s]/i)) {
return
}
return new Uint8Array(
hexString.match(/[\dA-F]{2}/gi).map(function(s) {
return parseInt(s, 16)
})
).buffer
}
我正在尝试验证从 WebHook 收到的 HMAC 签名。 WebHook 的详细信息是 https://cloudconvert.com/api/v2/webhooks#webhooks-events
这表示 HMAC 是使用 hash_hmac (PHP) 生成的,并且是正文的 SHA256 散列 - 即 JSON。收到的示例是:
c4faebbfb4e81db293801604d0565cf9701d9e896cae588d73ddfef3671e97d7
这看起来像是小写的十六进制。
我正在尝试使用 Cloudflare Workers 来处理请求,但是我无法验证哈希。我的代码如下:
const encoder = new TextEncoder()
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
const contentType = request.headers.get('content-type') || ''
const signature = request.headers.get('CloudConvert-Signature')
let data
await S.put('HEADER', signature)
if (contentType.includes('application/json')) {
data = await request.json()
await S.put('EVENT', data.event)
await S.put('TAG', data.job.tag)
await S.put('JSON', JSON.stringify(data))
}
const key2 = await crypto.subtle.importKey(
'raw',
encoder.encode(CCSigningKey2),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
)
const signed2 = await crypto.subtle.sign(
'HMAC',
key2,
encoder.encode(JSON.stringify(data))
)
await S.put('V22', btoa(String.fromCharCode(...new Uint8Array(signed2))))
return new Response(null, {
status: 204,
headers: {
'Cache-Control': 'no-cache'
}
})
}
这将生成一个散列:
e52613e6ecebdf98bb085f04ca1f91bf9a5cf1dc085f89dcaa3e5fbf5ebf1b06
我试过使用 crypto.subtle.verify 方法,但没有用。
有人能看出代码有什么问题吗?或者是否已使用 Cloudflare Workers 成功完成此操作?
马克
我终于使用验证方法完成了这个工作(我之前尝试过验证方法,但没有成功)。主要问题似乎是使用 request.json() 包装在 JSON.stringify 中。将其更改为 request.text() 解决了该问题。然后我可以在验证签名后使用 JSON.parse 来访问数据。代码如下:
const encoder = new TextEncoder()
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
const signature = request.headers.get('CloudConvert-Signature')
const key = await crypto.subtle.importKey(
'raw',
encoder.encode(CCSigningKey2),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['verify']
)
const data = await request.text()
const verified = await crypto.subtle.verify(
'HMAC',
key,
hexStringToArrayBuffer(signature),
encoder.encode(data)
)
if (!verified) {
return new Response('Verification failed', {
status: 401,
headers: {
'Cache-Control': 'no-cache'
}
})
}
return new Response(null, {
status: 204,
headers: {
'Cache-Control': 'no-cache'
}
})
}
function hexStringToArrayBuffer(hexString) {
hexString = hexString.replace(/^0x/, '')
if (hexString.length % 2 != 0) {
return
}
if (hexString.match(/[G-Z\s]/i)) {
return
}
return new Uint8Array(
hexString.match(/[\dA-F]{2}/gi).map(function(s) {
return parseInt(s, 16)
})
).buffer
}