Magento – Securing add to cart http request

apihttpsSecurity

I have a Magento site which integrates with a Javascript based product configurator using reverse proxy on a specific CMS page. The user configures their product and then hits 'Add to Cart' at which point the Javascript app passes a parameterised querystring back to the Magento cart controller via an http request.

It works great. It looks totally seamless from the user's point of view, they have no idea the Javascript app is on another domain and server. It's based on this concept;

http://www.magentocommerce.com/wiki/4_-_themes_and_template_customization/catalog/adding_a_product_to_the_cart_via_querystring

However…..it's not secure, it would just take sniffing and manipulating the http request to alter the product price. At the moment there is no SSL on the site as they are using Paypal offsite checkout.

My question: What is the best way to either harden this process or
change it so that it's more robust?

The options, as far as I can see, include the following but I'd be grateful for some more or some insight on these.

1. Use and SSL and secure urls

Could it be as simple as doing this? I know I can extend things relatively easily so the cart uses https by default;

http://fishpig.co.uk/blog/secure-https-magento-shopping-cart.html

2. Using URL encoding

At the moment the http request passes an unencoded querystring. I know that you can set the Magento add to cart url as something like this;

/checkout/cart/add/uenc/aHR0cDovL2Rldi5jaXJjdWl0Z2FsbGVyeS5jb20vZGV2aWwtcy1kZW4uaHRtbA/product/29/

But I have no idea how to do that.

File: app/code/core/Mage/Checkout/Helper/Cart.php

has a getAddUrl() method which uses the constant PARAM_NAME_URL_ENCODED, which I interpret as being a backend configuration setting;

   $params = array(
        Mage_Core_Controller_Front_Action::PARAM_NAME_URL_ENCODED => Mage::helper('core')->urlEncode($continueShoppingUrl),
        'product' => $product->getId()
  );

It is set here: app/code/core/Mage/Core/Controller/Varien/Action.php (line 51). Which backend setting is that though? Is that System->Configuration->General->Web->Secure->Use Secure URLs in Frontend? I thought that related to https rather than encoding.

If I do use this the trouble is that urlencode is just a base64 encoding;

File: app/code/core/Mage/Core/Helper/Abstract.php

public function urlEncode($url)
{
    return strtr(base64_encode($url), '+/=', '-_,');
}

There's no salt or encryption key, it seems that it's the urlDecode method that uses getEncryptedSessionId() via the sessionUrlVar() method;

public function urlDecode($url)
{
     $url = base64_decode(strtr($url, '-_,', '+/='));
     return Mage::getSingleton('core/url')->sessionUrlVar($url);
}

I don't get this. Surely someone could still sniff the http request, base64 decode it, change it and then re-encode it? Why use a session ID when decoding and nothing at all when encoding?

3. Add to cart via the Web Services API

Using the API seems like a better idea and fundamentally more secure;

http://www.magentocommerce.com/api/soap/checkout/cartProduct/cart_product.add.html

the only problem is that it's more troublesome from the Javascript side (although I did find some resources on JS integration with Magento API using titanium and nodejs for both SOAP and XML-RPC);

http://qzaidi.github.io/2011/10/16/magento-node/

https://github.com/milewise/node-soap

How to access the Magento API from native client with JavaScript

However, we already have a working implementation so I'd rather securing the existing working process if possible.

Best Answer

Unless the product configurations are confidential, adding TLS (https) won't help making the system more tamper proof. TLS is on the transport layer, the product configuration is the payload on the application layer.

URL parameter encryption can always be cracked, which is extremely easy if the encryption is done client side. So once again, unless the data itself is confidential, it would not help making the system tamper proof.

The only way to make sure the data from the JavaScript request hasn't been tampered with is server side validation.

Since the app is running on a external server, you probably don't want to duplicate the involved business logic and price rules in Magento.

The usual way to handle such a situation is to add a validation API to the application on the external server, so Magento can then check if the request was tampered with.

That could be verifying a simple hash of the request data, or duplicating the request to check the prices or multiple verifications from the heaps possible.

The general flow would then look like this:

  1. Customer configures a product using the JavaScript interface from the third party server.
  2. The resulte is then sent as a HTTP request to Magento.
  3. Magento receives the data and validates it's legit with the third party server.
Related Topic