Typeform Security API和Django:未正确验证哈希

问题描述 投票:1回答:1

我正在尝试将Typeform的安全性用于其Webhooks。这涉及

1) Receiving the signed packets and extracting the signature
2) Getting the body of the requst
3) Creating a hash with a secret key on the payload
4) Matching the hash with the received signature

我的网络框架是Django(基于Python)。我在此处的TypeForm链接中关注以下示例:https://developer.typeform.com/webhooks/secure-your-webhooks/

为了我的一生,我不知道发生了什么。我在Python和Ruby中都尝试过,但无法正确获得哈希值。我从Python调用了Ruby脚本来匹配输出,但是它们是不同的,而且都不起作用。有人有见识吗?我开始认为它可能与Django发送请求正文的方式有关。有人有任何输入吗?

Python实现:

import os
import hashlib
import hmac
import base64
import json


class Typeform_Verify:
    # take the request body in and encrypt with string
    def create_hash(payload):
        # convert the secret string to bytes 
        file = open("/payload.txt", "w") 
        # write to a payload file for the ruby script to read later
        file.write(str(payload))
        # access the secret string
        secret = bytearray(os.environ['DT_TYPEFORM_STRING'], encoding="utf-8")
        file.close()
        # need to have the ruby version also write to a file
        # create a hash with payload as the thing 
        #   and the secret as the key`
        pre_encode = hmac.new(secret,
            msg=payload, digestmod=hashlib.sha256).digest()
        post_encode = base64.b64encode(pre_encode)
        return post_encode

    # another approach is to make a ruby script 
    #   that returns a value and call it from here
    def verify(request):
        file = open("/output.txt", "w")
        # check the incoming hash values
        received_hash = request.META["HTTP_TYPEFORM_SIGNATURE"] 
        # create the hash of the payload
        hash = Typeform_Verify.create_hash(request.body)
        # call ruby script on it
        os.system(f"ruby manager/ruby_version.rb {received_hash} &> /oops.txt") 
        # concatenate the strings together to make the hash
        encoded_hash = "sha256=" + hash.decode("utf-8")
        file.write(f"Secret string: {os.environ['DT_TYPEFORM_STRING']}\n")
        file.write(f"My hash    : {encoded_hash}\n")
        file.write(f"Their hash : {received_hash}\n")
        file.close()
        return received_hash == encoded_hash 

Ruby脚本(从Python调用)

require 'openssl'
require 'base64'
require 'rack'
def verify_signature(received_signature, payload_body, secret)
  hash = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), secret, payload_body)
  # the created signature
  actual_signature = 'sha256=' + Base64.strict_encode64(hash) 
  # write created signature to the file
  out_file = File.new("/output.txt", "a")
  out_file.write("Ruby output: ")
  out_file.write(actual_signature)
  out_file.close()
  return 500, "Signatures don't match!" unless Rack::Utils.secure_compare(actual_signature, received_signature)
end

# MAIN EXECUTION 
# get the hash from the python scriupt
received_hash = ARGV[0]
# read the content of the file into the f array 
    # note that this is the json payload from the python script
f = IO.readlines("/payload.txt")
# declare the secret string
secret = "SECRET"
# call the funtion with the recieved hash, file data, and key
result = verify_signature(received_hash, f[0], secret) 

代码输出:

Typeform hash:   sha256=u/A/F6u3jnG9mr8KZH6j8/gO+Uny6YbSYFz7+oGmOik=
Python hash:     sha256=sq7Kl2qBwRrwgGJeND6my4UPli8rseuwaK+f/sl8dko=
Ruby output:     sha256=BzMxPZGmxgOMeJ236eAxSOXj85rEWI84t+6CtQBYliA=
django ruby hash webhooks typeform
1个回答
0
投票
这个想法是,您的请求应该签名。这是一个更基本的纯红宝石示例,应说明其工作原理。

# test.rb ENV['SECRET_TOKEN'] = 'foobar' require 'openssl' require 'base64' require 'rack' def stub_request(body) key = ENV['SECRET_TOKEN'] digest = OpenSSL::Digest.new('sha256') hmac_signature = OpenSSL::HMAC.hexdigest(digest, key, body) { body: body, hmac_signature: hmac_signature } end def verify_signature(payload_body, request_signature) digest = OpenSSL::Digest.new('sha256') hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), ENV['SECRET_TOKEN'], payload_body) if Rack::Utils.secure_compare(request_signature, hmac) puts "They match" else puts "They don't match" end puts "request_signature: #{request_signature}" puts " hmac: #{hmac}" puts " body: #{payload_body}" end request = stub_request(ARGV[0]) verify_signature(request[:body], request[:hmac_signature])

现在进行测试,只需运行:

ruby test.rb 'this is some random body string'
© www.soinside.com 2019 - 2024. All rights reserved.