练习 - 使用密码保护 Webhook 有效负载

已完成

在本练习中,你将使用机密保护 Webhook 有效负载,并了解如何使用 Azure 函数验证实际来自 GitHub 的有效负载。

获取 Azure 函数的密钥

  1. 在 Azure 门户中,返回到在模块中的第一个练习中创建的函数应用。

  2. 在左侧菜单窗格中的“函数”下,选择“函数”。 此时将显示函数应用的“函数”窗格。

  3. 选择创建的 HttpTrigger1。 此时将显示函数的“HttpTrigger1”窗格。

  4. 在左侧菜单窗格的“开发人员”下,选择“代码 + 测试”。 此时将显示函数的“代码 + 测试”窗格。

  5. 在函数的 index.js JavaScript 文件中,在文件开头的 module.exports 语句上方的添加对“crypto-js”库的引用。

    const Crypto = require('crypto');
    
  6. 在顶部菜单栏中,选择“保存”。 窗格底部将显示“日志”窗格。

  7. 在左侧菜单窗格的“开发人员”下,选择“函数密钥”。 此时将显示函数的“函数密钥”窗格。

  8. 在“值”列下,选择“显示值”链接

  9. 选择“复制到剪贴板”图标,并保存此密钥以便在下一步中使用。

  10. 在左侧菜单窗格的“开发人员”下,选择“代码 + 测试”。 此时将显示函数的“代码 + 测试”窗格。

  11. 在代码块中,在 context.log 语句之后,添加以下代码。 使用刚复制到剪贴板的默认密钥替换 <default key>

    const hmac = Crypto.createHmac("sha1", "<default key>");
    const signature = hmac.update(JSON.stringify(req.body)).digest('hex');
    

    此代码使用与 GitHub 相同的机制计算密钥的哈希值。

  12. 添加另一个 const,将 sha1= 追加到密钥开头,使它与请求头中的 x-hub-signature 格式一致。 将以下代码添加到函数。

    const shaSignature = `sha1=${signature}`;
    
  13. 请添加以下代码,以从请求标头中检索 GitHub 签名:

    const gitHubSignature = req.headers['x-hub-signature'];
    
  14. 比较这两个字符串。 如果它们一致,则处理该请求,如下所示:

    if (!shaSignature.localeCompare(gitHubSignature)) {
        // Existing code
        if (req.body.pages[0].title) {
            ...
        }
        else {
            ...
        }
    }
    
  15. 如果字符串不一致,则返回 HTTP 401(未经授权)响应,并且显示一条消息,告知发送方签名不一致。

    if (!shaSignature.localeCompare(gitHubSignature))
    {
        ...
    }
    else {
        context.res = {
            status: 401,
            body: "Signatures don't match"
        };
    }
    
    

    完成的函数应如下所示:

    const Crypto = require('crypto');
    
    module.exports = async function (context, req) {
        context.log('JavaScript HTTP trigger function processed a request.');
    
        const hmac = Crypto.createHmac("sha1", "<default key>");
        const signature = hmac.update(JSON.stringify(req.body)).digest('hex');
        const shaSignature =  `sha1=${signature}`;
        const gitHubSignature = req.headers['x-hub-signature'];
    
        if (!shaSignature.localeCompare(gitHubSignature)) {
            if (req.body.pages[0].title) {
                context.res = {
                    body: "Page is " + req.body.pages[0].title + ", Action is " + req.body.pages[0].action + ", Event Type is " + req.headers['x-github-event']
                };
            }
            else {
                context.res = {
                    status: 400,
                    body: ("Invalid payload for Wiki event")
                }
            }
        }
        else {
            context.res = {
                status: 401,
                body: "Signatures don't match"
            };
        }
    };
    
  16. 在顶部菜单栏中,选择“保存”。 此时将显示“日志”窗格,其中显示“已连接!”语句。

更新 Webhook 密码

  1. 切换到 GitHub 门户中的 GitHub 帐户。

  2. 选择存储库。

  3. 在顶部菜单栏中,选择“设置”。 随即将显示“设置”窗格。

  4. 在边栏中,选择“Webhooks”。 此时将显示“Webhook”页。

  5. 选择 Webhook 旁边的“编辑”。

  6. 在“机密”文本框中,输入你之前在本练习中保存的函数的默认密钥。

  7. 向下滚动到页面底部,然后选择“更新 Webhook”。 此时将显示“Webhooks/管理 Webhook”窗格。

测试 Webhook 和 Azure 函数

  1. 选择“最近提交”选项卡。

  2. 通过选择省略号 (...) 按钮,选择最新的(顶部)提交条目。

  3. 选择“Redeliver”。 在出现的“重新提交有效负载?”​​对话框中,选择“是的,请重新提交此有效负载”。

    此操作模拟你再次编辑 Wiki 页面。

  4. 通过选择省略号 (...) 按钮,选择最新的(顶部)提交条目。

  5. 在“标头”部分中,你将看到 x-hub-signature。 还会看到响应代码为 200,表示请求已成功处理。

    Request URL: https://testwh123456.azurewebsites.net/api/HttpTrigger1?code=aUjXIpqdJ0ZHPQuB0SzFegxGJu0nAXmsQBnmkCpJ6RYxleRaoxJ8cQ%3D%3D
    Request method: POST
    content-type: application/json
    Expect:
    User-Agent: GitHub-Hookshot/16496cb
    X-GitHub-Delivery: ce122460-6aae-11e9-99d4-de6a298a424a
    X-GitHub-Event: gollum
    X-Hub-Signature: sha1=<hash of default key>
    

测试无效签名

  1. 在 GitHub 门户中的 Webhook 页上,选择“设置”选项卡。

  2. 在“机密”测试框中,选择“更改机密”。

  3. 输入随机字符串,向下滚动,然后选择“更新 Webhook”。

    Webhook 使用的密钥不再与 Azure 函数所需要的密钥一致。

  4. 选择“最近提交”选项卡。

  5. 通过选择省略号 (...) 按钮,选择最新的(顶部)提交条目。

  6. 选择“重新提交”,然后在出现的“重新提交有效负载”​​对话框中,选择“是的,请重新提交此有效负载”。

  7. 此时还会看到响应代码为 401,表示请求未经授权。

  8. 通过选择省略号按钮 (...),选择最新的(顶部)提交条目(重新提交)。

  9. 选择“响应”选项卡,然后在“正文”部分中,验证是否显示“签名不匹配”消息。