如何在HAProxy中验证HMAC

时间:2019-09-06 15:44:29

标签: haproxy sha256 hmac sonarcloud

是否可以在HAProxy中检查HMAC有效性?理想情况下,如果HMAC有效,我想设置一个acl,以便可以在规则中使用它。

我们的Ubuntu 18.04构建服务器(运行Jenkins)位于防火墙后面,防火墙仅列出了特定的IP范围。

我们有一个HAProxy(1.8)实例,它接收所有入站请求并路由到适当的后端服务。

问题在于SonarCloud已将其Webhooks从一组定义的IP地址更改为使用HMAC来验证真实性。这意味着除非我们向所有互联网流量开放,否则Webhooks将被防火墙阻止。

https://sonarcloud.io/documentation/project-administration/webhooks/#securing-your-webhooks

如果我们可以配置HAProxy来验证HMAC,那么我们可以向所有流量打开服务器并使用HAProxy来验证这些请求(以及其他现有的IP白名单范围)。

2 个答案:

答案 0 :(得分:1)

HAProxy本身并不执行HMAC,但是可以使用HAProxy的Lua集成来完成。

一种方法是找到一个可以满足所需HMAC风格的Lua库,然后在Lua中编写一个HAProxy转换器以获取适当的输入并计算摘要以进行比较。

我曾经使用带有Lua 5.x的HAProxy 1.6实现了类似的操作,其中客户端发送了使用HMAC-SHA1签名的URL,并且代理成功检查了其有效性。

不幸的是,我不再有权访问该代码,但我写了this HAProxy converter to do utf-8-aware URL-escaping (percent encoding) in Lua ...之所以在此提及,是因为它是使用Lua扩展HAProxy功能的一种完整方法,包括Lua代码。和HAProxy配置需要使用它,因此它可以帮助您寻求解决方案。

答案 1 :(得分:1)

感谢Michael提供了指向HAProxy / Lua集成的指针。我的解决方案在这里注明以供参考。

创建以下Lua脚本(hmac_validate.lua):

hmac = require('openssl.hmac')

local function tohex(s)
    return (string.gsub(s, ".", function (c)
        return string.format("%.2x", string.byte(c))
    end))
end -- tohex

function validate_sonar_hmac(txn, hmac_header_key, hmac_secret)
    local payload = txn.req:dup() -- take a copy of the request content
    local body = string.sub(payload,string.find(payload,"\r\n\r\n")+4) -- strip off the headers
    local signature = txn.sf:req_fhdr(hmac_header_key) -- get the HMAC signature sent on the request

    -- calculate hmac from body & secret
    local sc_hmac = hmac.new(hmac_secret, "sha256")
    local calculated_signature = tohex(sc_hmac:final(body))

    local signatures_match = calculated_signature == signature
    if not signatures_match then
        core.Alert("Sonar Cloud HMAC signature mismatch - received '"..signature.."' but calculated '"..calculated_signature.."'")
    end

    txn:set_var("req.sonar_request_valid", signatures_match)
end;

core.register_action("validate-sonar-hmac", {"http-req"}, validate_sonar_hmac, 2)

HA代理配置更改为添加以下行:

global
    lua-load /etc/haproxy/hmac_validate.lua

frontend
    acl sonarcloud hdr(X-Sonar-Webhook-HMAC-SHA256) -m found
    http-request lua.validate-sonar-hmac X-Sonar-Webhook-HMAC-SHA256 {{ sonarcloud_hmac_secret }} if sonarcloud
    http-request deny if sonarcloud !{ var(req.sonar_request_valid) -m bool }