1
votes

I'm having trouble with CORS in my e-commerce set up and my understanding of CORS.

I have a React app (Gatsby) hosted on AWS S3. The CORS configuration is set up as:

<?xml version="1.0" encoding="UTF-8"?>
  <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
      <AllowedOrigin>*.example.com</AllowedOrigin>
      <AllowedMethod>GET</AllowedMethod>
      <AllowedMethod>PUT</AllowedMethod>
      <AllowedMethod>POST</AllowedMethod>
      <AllowedMethod>DELETE</AllowedMethod>
      <AllowedMethod>HEAD</AllowedMethod>
      <AllowedHeader>*</AllowedHeader>
    </CORSRule>
  </CORSConfiguration>

I've got this set up on a Cloudfront distribution. I've changed my Security Policy to TLSv1.2_2018 as per the Stripe Docs. For Gatsby to work it needs the origin to be set to the real bucket name: www.example.com.s3-website-eu-west-1.amazonaws.com as S3 doesn’t look for index.html files when serving its clean URLs. I've added a behaviour to change http to https. I've set Allowed HTTP Methods to GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE and whitelised origin headers.

I'm using Stripe's checkout.js to collect card details and create orders using fetch. Here's my function:

async onToken (token, args) {
  try {
    let response = await fetch(process.env.STRIPE_CHECKOUT_URL, {
      method: 'POST',
      headers: {
        'Access-Control-Allow-Origin': '*'
      },
      body: JSON.stringify({
        token,
        order: {
          currency: this.props.currency,
          coupon: this.props.coupon,
          items: [
            {
              type: 'sku',
              parent: this.props.skuId
            }
          ],
          shipping: {
            name: args.shipping_name,
            address: {
              line1: args.shipping_address_line1,
              city: args.city,
              postal_code: args.shipping_address_zip
            }
          }
        }
      })
    })

    let orderJson = await response.json()
  } catch(err) {
    alert(err)
  }
  history.push({
    pathname: '/thankyou/',
    state: { orderId: orderJson.order.id }
  })
  history.go()
}

So, this calls a AWS Lambda function:

const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY)

module.exports.handler = (event, context, callback) => {
  const requestBody = JSON.parse(event.body)

  // token info
  const token = requestBody.token.id
  const email = requestBody.token.email

  // order info
  const currency = requestBody.order.currency
  const items = requestBody.order.items
  const shipping = requestBody.order.shipping
  const coupon = requestBody.order.coupon

  // Create order
  return stripe.orders.create({
    email: email,
    coupon: coupon.id,
    currency: currency,
    items: items,
    shipping: shipping
  }).then((order) => {

    // Pay order with received token (from Stripe Checkout)
    return stripe.orders.pay(order.id, {
      source: token // obtained with Stripe.js
    }).then((order) => {
      const response = {
        statusCode: 200,
        headers: {
          'Access-Control-Allow-Origin': '*'
        },
        body: JSON.stringify({
          message: `Order processed succesfully!`,
          order
        })
      }
      callback(null, response)
    })
  }).catch((err) => { // Error response
    console.log(err)
    const response = {
      statusCode: 500,
      headers: {
        'Access-Control-Allow-Origin': '*'
      },
      body: JSON.stringify({
        error: err.message
      })
    }
    callback(null, response)
  })
}

When I test the payments - I get an error:

"failed to load {lambda function url}": Response to preflight request 
doesn't pass access control check: No 'Access-Control-Allow-Origin' 
header is present on the requested resource. 'https://www.example.com' 
is therefore not allowed to access. The response had HTTP status code 
403..."

My SSL cert is set up for *.example.com

Is this implementation secure and why is it failing the access control check?

1
Can you verify that your Lambda function is returning the Access-Control-Allow-Origin headers? curl -s -I -X POST http://example.com/your-lambda-function-here/ - tekniskt

1 Answers

1
votes

This turned out to be a problem with the API Gateway settings. Enabling CORS and deleting the headers from the calling function got this to work.