Customers wanted to add coupon codes to their site. My first reaction was "ZOMG. Who can issue coupons? Do they expire? How do we avoid using a coupon more than once? What if a transaction fails? etc.". The customers were much more relaxed about it and showed me what "the others" were doing (we even had a real coupon code to test things with): they seem to use [manually generated] Paypal hosted buttons so there must be a very small number of coupon codes (most probably - there's only one).
So what's the "threat" model?
Here's a trick that only requires static html: we keep a file for each coupon (the coupon code is the filename), and those files contain html snippets (e.g. a paypal pay button for buying the same product at a discount). We try to fetch the url corresponding to the code entered by the user and either succeed (present the discounted button[s]) or fail (gracefully).
Never knew people needed such things. Turns out they do, so there you have it :)
xxxxxxxxxx
<html lang="en">
<head>
<title>Pseudo-secure coupon code</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<div id="status">
Enter coupon code (if you have one)
<small>Spoiler: there are 2 coupon codes: <code>vip23</code> and <code>hip42</code> :)</small>
</div>
<div id="discount-code" action="" method="get">
<form action="" method="get">
<input name="code" type="password" size=6>
<input type="submit" value="I have one">
</form>
</div>
<div id="buy-button">
<button onclick="alert('this can be a paypal button or whatever')">Buy a widgit for $10</button>
</div>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
if (location.search) {
$('#status').html('Checking...');
var coupon = /code=([a-zA-z0-9]+)/.exec(location.search);
if (coupon) {
coupon = coupon[1]; // only the [...]+ part
$.ajax({
'url':coupon,
'dataType':'html',
'success':function(data) {
$('#status').empty();
$('#discount-code').empty();
$('#buy-button').html(data);
},
'error':function() {
$('#status').html('Bad coupon code');
},
});
} else { // maybe keyboard is in non-English mode, maybe a script kiddie tries "../" :)
$('#status').html('Bad coupon code');
}
}
});
</script>
</body></html>
Modified http://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js to a secure url
https://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js