我收到 Stripe 签名错误:#<Stripe::SignatureVerificationError: Nosignatures found matches the Expected Signature for Payload>

Pau*_*uli 1 ruby ruby-on-rails webhooks stripe-payments

我目前正在处理我的 Webhooks,但我的 Webhooks 控制器中出现错误。

这是错误:

#<Stripe::SignatureVerificationError: No signatures found matching the expected signature for payload>
No template found for WebhooksController#create, rendering head :no_content
Completed 204 No Content in 1ms (Allocations: 594)
Run Code Online (Sandbox Code Playgroud)

经过一段时间尝试调试这个问题后,我发现它来自这些行,因为我在控制台中看到的最后一个代码是错误和“签名错误”...

rescue Stripe::SignatureVerificationError => e
      # Invalid signature
      puts "Signature error"
      p e
      return
    end
Run Code Online (Sandbox Code Playgroud)

这是控制器:

class WebhooksController < ApplicationController
  skip_before_action :authenticate_user!
  skip_before_action :verify_authenticity_token

  def create
    payload = request.body.read
    sig_header = request.env['HTTP_STRIPE_SIGNATURE']
    event = nil

    begin
      event = Stripe::Webhook.construct_event(
        payload, sig_header, Rails.application.credentials[:stripe][:webhook]
      )
    rescue JSON::ParserError => e
      status 400
      # Invalid payload
      puts "Payload error"
      return
    rescue Stripe::SignatureVerificationError => e
      # Invalid signature
      puts "Signature error"
      p e
      return
    end


    # Handle the event
    case event.type
    when 'checkout.session.completed'
      booking = Booking.find_by(checkout_session_id: event.data.object.id)
      booking.update(paid: true)
      booking.save

      # @booking = Booking.where(checkout_session_id: event.data.object.id)
      # @booking.update(paid: true)
      # @booking.save
    end

    render json: { message: 'success' }
  end
end
Run Code Online (Sandbox Code Playgroud)

任何帮助都会很棒,因为我已经为此苦苦挣扎了一段时间。

koo*_*jah 5

验证 Webhook 签名通常会因 2 个具体原因而失败:

  1. 使用错误的 webhook 密钥
  2. 传递与 Stripe 实际发送给您的负载不同的负载

第一个相当容易调试,但它却困扰了很多开发人员。当您创建 WebhookEndpoint(在 API 或仪表板中)时,您会得到一个secret看起来像whsec_12334ABC.... 您需要确保您的代码使用该确切的秘密才能验证签名。请注意,如果您使用 Stripe CLI 来测试此流程,它会为您提供一个不同的秘密,在这种情况下您必须使用该特定秘密。

如果您确信自己使用的是正确的秘密,那么第二个常见的根本原因是有效负载的内容。当 Stripe 生成签名时,它会在特定版本的有效负载上以 JSON 形式进行签名。为了验证签名,您必须使用完全相同的有效负载。

问题在于,许多 Web 框架(例如 Express for Node.js 或 Rails for Ruby)都会篡改原始有效负载。当它收到请求时,它会看到 JSON,因此它会尝试为您提供帮助并解析数据。然后,当您请求内容时,它不会向您提供原始内容/有效负载,而是将 JSON 重新序列化为字符串。这样做通常会更改原始有效负载,例如删除/添加空格/缩进或更改属性本身的顺序。如果有效负载与 Stripe 发送给您的内容不同,则签名无法匹配,因此会出错。

使用 Rails,您可能想要尝试request.raw_post或找到类似的解决方案来获取发送给您的确切原始 JSON。