При настройке подписи Stripe Webhook следует ли отклонять неподписанные события?

#node.js #stripe-payments

Вопрос:

Я настраиваю платежи по подписке с полосой, следуя этому руководству.

На шаге 4 (предоставление и мониторинг подписок) Полоса указывает нам настроить веб-справочник для обработки событий подписки.

Когда событие webhook получено, его подпись может быть аутентифицирована, чтобы убедиться, что оно было отправлено Stripe, а не злонамеренной третьей стороной.

Но в их примере кода сразу после проверки подлинности подписи они включают else блок для извлечения данных о событиях непосредственно из тела запроса для неподписанных событий.

Я не понимаю, почему они включили это. Разве это не должно быть одно или другое вместо того, чтобы допускать и то, и другое?

Я понимаю, что наличие обоих сводит на нет смысл аутентификации webhook, потому что теперь разрешены как подписанные, так И неподписанные события.

Если у меня настроена регистрация на веб-сайте, должен ли я удалить этот else блок?

Вы можете увидеть пример кода ниже в строках 28-33.

 // Set your secret key. Remember to switch to your live secret key in production.
// See your keys here: https://dashboard.stripe.com/apikeys
const stripe = require('stripe')('API_KEY_GOES_HERE');

app.post("/webhook", async (req, res) => {
  let data;
  let eventType;
  // Check if webhook signing is configured.
  const webhookSecret = {{'STRIPE_WEBHOOK_SECRET'}}
  if (webhookSecret) {
    // Retrieve the event by verifying the signature using the raw body and secret.
    let event;
    let signature = req.headers["stripe-signature"];

    try {
      event = stripe.webhooks.constructEvent(
        req.body,
        signature,
        webhookSecret
      );
    } catch (err) {
      console.log(`⚠️  Webhook signature verification failed.`);
      return res.sendStatus(400);
    }
    // Extract the object from the event.
    data = event.data;
    eventType = event.type;
  } else {
    // Webhook signing is recommended, but if the secret is not configured in `config.js`,
    // retrieve the event data directly from the request body.
    data = req.body.data;
    eventType = req.body.type;
  }

  switch (eventType) {
      case 'checkout.session.completed':
        // Payment is successful and the subscription is created.
        // You should provision the subscription and save the customer ID to your database.
        break;
      case 'invoice.paid':
        // Continue to provision the subscription as payments continue to be made.
        // Store the status in your database and check when a user accesses your service.
        // This approach helps you avoid hitting rate limits.
        break;
      case 'invoice.payment_failed':
        // The payment failed or the customer does not have a valid payment method.
        // The subscription becomes past_due. Notify your customer and send them to the
        // customer portal to update their payment information.
        break;
      default:
      // Unhandled event type
    }

  res.sendStatus(200);
});
 

Комментарии:

1. Если у вас нет настроенного секрета webhook, ваши данные будут извлечены, вы проверяете сервер подписи, используя секретный ключ, чтобы можно было передавать неподписанные события, но безопасно иметь подписанное событие, потому что любой плохой субъект может отправить запрос, например, манипулировать заказом

2. @SachinAnanthakumar так ты говоришь, что я должен сохранить и то, и другое? В этом случае проверка подписи кажется бессмысленной, потому что я также прохожу через события, которые не подписаны.

3. Рекомендуется, чтобы событие webhook было подписано, stripe использует ваш закрытый ключ для подписи, а затем может быть проверено вами на стороне сервера, рекомендуется, чтобы все веб-крючки были подписаны. таким образом, любые неподписанные подписи принадлежат плохим участникам, и вы можете использовать класс else для хранения журналов в целях безопасности

4. @SachinAnanthakumar вот что я подумал. Так почему же пример кода полосы допускает и то, и другое? Вот какой вопрос я задаю. Я не спрашиваю, что такое подпись веб-крючка или зачем она нужна. Я спрашиваю, почему их пример кода допускает как подписанные, так и неподписанные события.

5. хороший вопрос, есть некоторые важные события, такие как платные, и некоторые менее важные события, которые не имеют значения и используются только для регистрации, и некоторые пользователи не хотят проверять подпись, поэтому stripe позволяет и то, и другое, лучше всего, чтобы все события были подписаны.

Ответ №1:

Я напрямую связался со Stripe, и они посоветовали: «это должно быть то или иное, а не то и другое».

Поэтому, если у вас настроена настройка подписи Webhook, вам следует удалить аутентификацию подписи из if/else блока, тем самым сделав if/else ее бесполезной, поэтому удалите и это.

Вот обновленная версия:

 // Set your secret key. Remember to switch to your live secret key in production.
// See your keys here: https://dashboard.stripe.com/apikeys
const stripe = require('stripe')('API_KEY_GOES_HERE');

app.post("/webhook", async (req, res) => {

  // Check if webhook signing is configured.
  const webhookSecret = {{'STRIPE_WEBHOOK_SECRET'}}

  // Retrieve the event by verifying the signature using the raw body and secret.
  let event;
  let signature = req.headers["stripe-signature"];

  try {
    event = stripe.webhooks.constructEvent(
      req.body,
      signature,
      webhookSecret
    );
  } catch (err) {
    console.log(`⚠️  Webhook signature verification failed.`);
    return res.sendStatus(400);
  }
  // Extract the object from the event.
  let data = event.data;
  let eventType = event.type;

  switch (eventType) {
      case 'checkout.session.completed':
        // Payment is successful and the subscription is created.
        // You should provision the subscription and save the customer ID to your database.
        break;
      case 'invoice.paid':
        // Continue to provision the subscription as payments continue to be made.
        // Store the status in your database and check when a user accesses your service.
        // This approach helps you avoid hitting rate limits.
        break;
      case 'invoice.payment_failed':
        // The payment failed or the customer does not have a valid payment method.
        // The subscription becomes past_due. Notify your customer and send them to the
        // customer portal to update their payment information.
        break;
      default:
      // Unhandled event type
    }

  res.sendStatus(200);
});