【问题标题】:Verify HMAC Hash Using Cloudflare Workers使用 Cloudflare Workers 验证 HMAC 哈希
【发布时间】:2021-06-08 16:32:23
【问题描述】:

我正在尝试验证从 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 成功地做到了这一点?

标记

【问题讨论】:

  • 如果在浏览器而不是 Cloudflare Workers 中执行,代码是否按预期工作?如果是这样,这可能是一个工人错误。如果它在浏览器中不起作用,那么您的问题可能更多是关于 WebCrypto API 的一般使用,而不是专门针对 Cloudflare Workers。
  • 不,即使在 Cloudflare Workers 之外,我仍然无法使哈希值匹配。我已经更新了我的标签

标签: webcrypto-api cloudflare-workers cloudconvert


【解决方案1】:

我终于用 verify 方法完成了这个工作(我之前尝试过 verify 方法,但没有用)。主要问题似乎是使用 JSON.stringify 包装的 request.json()。将此更改为 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
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-21
    • 2016-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多