【问题标题】:Github Webhooks secret with AWS API Gateway使用 AWS API Gateway 的 Github Webhooks 秘密
【发布时间】:2020-01-26 05:03:09
【问题描述】:

我正在尝试让 Github Webhook 启动我拥有的 AWS Lambda。 我能弄清楚如何做到这一点的最好方法是使用 AWS API Gateway,问题是安全性。

Github Webhooks 只会通过 POST 调用发送秘密。

我找不到任何方法让 AWS API Gateway 验证此签名。 或者我可以在哪里添加此功能。

我假设我可以写一个AWS Lambda Authorizer。 但是这是很多不同地方的代码,开始看到需要serverless 框架。

AWS 中是否有任何更简单的设置我不知道?

【问题讨论】:

    标签: amazon-web-services github git-webhooks github-webhook


    【解决方案1】:

    来到这里是因为我试图将 Github webhook 与 AWS lambda 集成并遇到与 OP 相同的问题。在撰写本文时,我认为最好的解决方案是在主 lambda 中包含验证码,正如其他人所建议的那样。

    在 2017 年 9 月的 AWS 计算机博客上:

    增强型请求授权器 Lambda 函数接收类似于代理集成的事件对象。它包含有关请求的所有信息,不包括正文。

    来源: Using Enhanced Request Authorizers in Amazon API Gateway (amazon.com)

    您无法按照 Github 的建议执行 HMAC,因为 AWS 授权器 lambda 不会让您访问 HTTP 请求的主体,而您需要它来比较摘要。

    这是一种耻辱,因为 HMAC 似乎是保护响应 webhook 的端点的一种非常标准的方法。例如,参见这篇博文,Webhooks do’s and dont’s: what we learned after integrating +100 APIs (restful.io)。 Twitter 和 Stripe 做了类似的事情:

    要使上述方法有效,如果您使用的是 API Gateway,您需要确保将包含哈希签名的标头作为 event 参数的一部分转发给 lambda。为此,请按照以下说明操作:How do I pass custom headers through Amazon API Gateway to an AWS Lambda function using custom Lambda integration for further processing? (amazon.com)

    【讨论】:

    • 实际上,我只是在一次会议上与 AWS Authorizer 产品经理交谈,他很失望地得知他自己无法做到这一点,因为您在这里所说的正是如此(无法访问有效负载反对),他的回应是在 Lambda 中进行。有点遗憾,您不能将他们的系统用于他们的最佳实践。这是一个惊人的回应,你赢得了这个答案!谢谢,希望我们能帮助许多其他人,直到 AWS 想出更好的方法来处理这个问题。
    【解决方案2】:

    我找不到使用 API Gateway 执行此操作的方法。我使用(Python)在 LAMBDA 中进行了验证。

    高级概述:使用 GITHUB_SECRET 计算 HMAC 签名,然后与从 Github 传递的签名进行比较。

    您显然可以简化,故意冗长以提高可读性。可能有更好的方法,但我找不到。

    确保您的 Webhook 已针对 application/json 进行了配置。希望这对其他人有帮助。

    import logging
    import json
    import hmac
    import hashlib
    import re
    from urllib.parse import unquote
    
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.DEBUG)
    
    GITHUB_SECRET = 'SECRET FROM GITHUB CONSOLE'
    
    
    def lambda_handler(event, context):
        logger.info("Lambda execution starting up...")
    
        incoming_signature = re.sub(r'^sha1=', '', event['headers']['X-Hub-Signature'])
        incoming_payload = unquote(re.sub(r'^payload=', '', event['body']))
        calculated_signature = calculate_signature(GITHUB_SECRET, incoming_payload.encode('utf-8'))
    
        if incoming_signature != calculated_signature:
            logger.error('Unauthorized attempt')
            return {
                'statusCode': 403,
                'body': json.dumps('Forbidden')
            }
    
        logger.info('Request successfully authorized')
    
        # do stuff in Lambda
    
        return {
            'statusCode': 200,
            'body': json.dumps(f'Work in progress')
        }
    
    
    def calculate_signature(github_signature, githhub_payload):
        signature_bytes = bytes(github_signature, 'utf-8')
        digest = hmac.new(key=signature_bytes, msg=githhub_payload, digestmod=hashlib.sha1)
        signature = digest.hexdigest()
        return signature
    

    【讨论】:

    • 感谢分享!是的,我实际上有您编写的用于在单独的 lambda 中进行验证的内容,但我需要它来返回策略和委托人 ID,我对应该发送什么 AWS 策略感到非常困惑?允许 API 网关的策略,或者允许我想要后台功能的实际 lambda。
    • 这就是我接下来要做的事情。以上假设您将内联完成授权,然后运行 ​​lambda 代码(都在同一个 lambda 中)。当我有时间让 lambda 返回 IAM 策略和委托人标识符时,我会分享。
    • 在此处出现错误 :( [ERROR] TypeError: expected string or bytes-like object Traceback (last recent call last): File "/var/task/lambda_function.py", line 21, in lambda_handler incoming_payload = unquote(re.sub(r'^payload=', '', event['body-json'])) 文件“/var/lang/lib/python3.8/re.py”,第 208 行, in sub return _compile(pattern, flags).sub(repl, string, count)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    • 2019-01-07
    • 2020-09-25
    • 2017-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多