May 18th 2009

Poor man's Google Checkout

Google Checkout recently gained support for taking recurring payments, a frequently requested enhancement for my Xen-based server.

However, to use any of the non-trivial features we must provide Google with a signed XML file for each transaction. This would normally preclude the use of some server-side scripting, but if the details of transaction are static there is no reason we shouldn't be able to generate the relevant HTML ahead-of-time.

The resulting HTML file can be hosted anywhere, is almost completely independent of the server configuration and greatly reduces the attack surface by being a simple static file. The main disadvantage of this approach (and indeed of this submission method in general) is that allows trivial replay attacks of previous transactions.

Anyway, first we create our request XML:

$ head -n6 order.xml
<?xml version="1.0" encoding="UTF-8"?>
<checkout-shopping-cart xmlns="http://checkout.google.com/schema/2">
 <shopping-cart>
   <items>
     <item>
       <item-name>Lunar object affixed to slender carrying attachment</item-name>

Next, we construct a simple template:

$ cat order.html.in
<h1>Order stuff</h1>
<form method="POST"
    action="https://checkout.google.com/api/checkout/v2/checkout/Merchant/__MERCHANT_ID__">
 <input type="hidden" name="cart" value="__CART__">
 <input type="hidden" name="signature" value="__SIGNATURE__">
 <input type="image" name="Google Checkout" alt="Fast checkout through Google"
   src="http://checkout.google.com/buttons/checkout.gif?merchant_id=__MERCHANT_ID__&w=180&h=46&style=white&variant=text&loc=en_US"
   height="46" width="180">
</form>

Finally, we generate the final page from the above files using the following Makefile:

MERCHANT_ID  = # Enter your merchant ID here
MERCHANT_KEY = # Enter your merchant key here

FILES = order.html

all: $(FILES)

%.html: %.html.in %.xml
       sed -e 's|__MERCHANT_ID__|$(MERCHANT_ID)|g' \
           -e 's|__CART__|'$$(base64 -w0 $*.xml)'|g' \
           -e 's|__SIGNATURE__|'$$( \
           openssl dgst -sha1 -hmac $(MERCHANT_KEY) -binary <$*.xml | base64 -w0)'|' \
           <$< >$@

clean:
       rm -f $(FILES)

.PHONY: clean
$ make
[...]
$ head -n4 index.html
<h1>Order stuff</h1>
<form method="POST"
    action="https://checkout.google.com/api/checkout/v2/checkout/Merchant/007">
 <input type="hidden" name="cart" value="iAgICAgICAgICAgIDxpdGVtLWRlc2NyaXB0aW9 [..]

Non-trivial dependencies are OpenSSL (to generate the HMAC-SHA-1 signature) and make. You should ensure that you don't upload or otherwise reveal your Makefile as it contains your merchant key.




You can subscribe to new posts via email or RSS.