This article will demonstrate a client-side, out-of-scope, payment processing technique that is available to Windows Azure programmers.
At first glance, collecting credit cards on websites appears pretty simple. Present the necessary input fields on your website in an HTML form; then post the collected information back to your server-side code which passes it on to a bank's gateway in return for lots of money. In a perfect and honorable world, that might be all that is required, but in the real world, handling credit cards is a lot more complicated.
The Payment Card Industry Data Security Standard (PCI DSS) governs the transmission of debit and credit card information. Websites, Website Servers and Database Storage Facilities must be PCI compliant before they are allowed to handle or store cardholder information. There are currently 12 requirements and an expensive audit involved in becoming compliant. Fundamental to the concept of PCI compliance is the edict that from the moment of collection on, no non-compliant server or database may even touch the card holder information. If one does, the entire process becomes invalid.
Azure itself is not PCI compliant. Although incredibly secure both physically and digitally, its data centers do not possess all of the necessary certifications yet. As a result, your website cannot process credit cards under the PCI guidelines, if the azure servers ever touch the collected cardholder information... directly.
The credit card industry offers two short-hand terms to categorize the programming techniques which work with a credit card holder’s sensitive information. “In-Scope” techniques directly access the credit card’s number, expiration-date and 3-4 digit security code. Web Servers, which use “In-Scope” techniques, are expected to meet the PCI-Compliance guidelines. “Out-of-Scope” techniques use various client-side techniques, such as cross-browser-ajax-posting and browser-redirection to keep the sensitive information away from your web-server; they allow a different machine, such as the payment gateway’s server, to perform the “In-Scope” information handling. In the process, they off-load much of the PCI compliance burden to that other machine. This article will focus solely on “Out-of-Scope” solutions, which by their nature can safely be used with Azure.
To demonstrate this client-side technique, I've created http://pay2see.azurewebsites.net, a simple MVC website containing two views and one controller. The index view contains a form to collect credit card information and a button which offers to charge two dollars against the provided credit card. It then displays the inner, “secure” view. There is no model or database attached at this point, but those will be added in the next challenge. This is therefore, a demonstration of credit card processing for a “pay per access” scenario in which the user has to pay each time they want to see the secured page. In the future, we will evolve this to a “subscription” scenario, where the user’s single payment allows them multiple viewings.
- This article is not an advertisement for SlimCD. They are just the payment gateway which I use. I have been told that BrainTree Payments and Stripe provide similar functionality, but I have no experience working with them.
- The payment processing code on this article’s azure website is completely functional and capable of transacting real world business, charging real credit cards in real dollars and crediting real merchant accounts with revenues. This article’s azure website however, is configured with a test merchant account so no real world business will occur, nor will real money be involved, when you test the site.
- To ease your testing of the site, default values have been loaded into many of the fields on the index view’s credit card entry form. These values are fake and will only work with the test merchant account which has been set up for this site.
- I am not guaranteeing that anything in this article is true. I am pretty sure of that my understanding of payment processing is current and that the techniques described here are out-of-scope for PCI compliance. Recheck everything here with your own PCI compliance expert or with the Merchant Service Provider/Bank which provides your merchant account.
The controller now uses the transaction token to charge two dollars against the associated credit card. It does this by submitting the token in a “processtransaction” request to the payment gateway. If the gateway then confirms that the charge has succeeded, the controller then changes the user’s browser to the secure view. This fulfills the “pay per access” scenario described above.
If anything goes wrong with the charge such as the card being invalid or over its limit, the controller would resend the index view to the user’s browser, along with an error message describing what went wrong.
At this point in the contest, that is all we will do with the transaction token; charge against it once and then throw it away. In the third challenge, we will persist the transaction token, using its presence as proof of its card holder’s right to revisit the secure page. In the fourth challenge we will be setting up a web service on a virtual machine, and that web service will use the transaction token to periodically recharge the user’s card, sustaining their subscription for accessing the site’s secure page. Transaction tokens are extremely useful tools for implementing a persistent and recurring charge relationship between a specific customer and a specific merchant, and we will explore that further in the later challenges of this contest.
UNDER THE HOOD (clientside : index view)
ProcessTransaction which handles the cross-browser, ajax-style posting. It accepts a json array, containing the merchant account information, the credit card information and a very important transaction type field. In this example, the merchant account information include the username, siteid and priceid lines, which are being loaded from string literals. The credit card information is loaded directly from the form’s inputs, and the transaction type is the string literal “LOAD”.
C). “LOAD” is the command which tells the credit card gateway to store the provided merchant/credit card information and to return a transaction token for future use.
UNDER THE HOOD (serverside : home controller)
So now we have our index view posting back to our controller with its sensitive fields cleared and with a hidden field called “transactiontoken” containing our newly created transaction token. All we have accomplished so far is to tokenize some data. No moneys have been moved.
The next step is to perform the actual charging of the card and that occurs on the server side, far from prying eyes. Let’s look at the index method of the homecontroller.
This C# method accepts posts from the Index view and then, if that view has passed in a transactiontoken value, it uses that token to charge the associated credit card. It does this by calling the C# version of that same ProcessTransactions method, this time using a transtype value of “SALE”. This transtype actually charges the card instead of just tokenizing it.
The highlights of this controller method include…
A). It receives the transaction token from the collection array. This works because out on the html form in the view, the transactiontoken hidden field had a name attribute. ASP.NET MVC loads named inputs into the collection array during post back. Notice that none of the sensitive information inputs have name attributes so they wouldn’t be passed to the server during an unexpected post. The transaction token gets stored in the gateid field of the ProcessTransactionRequest class.
C). The client transaction reference is a string which will be stored with the credit card transaction and may potentially show on the card holder’s statement. It is supposed to be a unique identity which the customer can use when talking to the merchant about this transaction. For example, the customer might say “Hi, I’m calling about my credit card purchase on January 3rd, invoice # 10043…” The 10043 is the client transaction reference. It doesn’t have to make any sense to the payment gateway, or the credit card provider, or the bank; but it should make sense to the merchant, helping them identify exactly which event this credit card transaction is paying for. For the sake of this example, I’m just using a random number, but that will change in the next challenge.
D). This time, the transtype value is ‘SALE’ which means (if we weren’t using a test merchant account) real money would be moving from the card holder’s bank to the merchant. Notice that this is also where we set the dollar amount of our sale, instead of out on the client side where a hacker might mess with it.
ProcessTransaction() completes, we extract the returned values from the reply class instance and load them into the viewbag. The secure view which we are about to call, displays those returned values as a simple receipt.
ProcessTransaction() returns an approval, we send the secure view to the customer’s browser.
G). If not, we update the error message and send them another copy of the index view.
A FEW WORDS ABOUT SECURITY
processTransactions() endpoint through which transactions can be fed. A malicious mind is barely necessary to imagine the kinds of trouble that can grow from this; until you factor in that the access credentials which we have exposed here, are nearly impotent.
THE PAYMENT GATEWAY CREDENTIAL THAT GETS EXPOSED ON THE CLIENT SIDE IS A ONE TRICK PONY…
It can only submit requests of transtype, ‘LOAD’. All other transtypes have been shut off at the gateway and will be ignored. The only thing which the exposed code and values can do, is submit information for tokenization…
AND TOKENIZATION IS A BLACK HOLE…
Requests with a transtype of ‘LOAD’ accept any stream of text and only return a token in reply. They do no validation of the provided information, returning a few easily calculated values such as the last four digits of the card number and it’s mathematically determined card-type. The token is the only potentially valuable morsel of information returned, and it is only valuable to someone with a higher-privileged access credential on the same merchant account.
Nothing that a hacker might get from the information exposed on the client-side, will help them in their attempts at theft or mischief.
On the server-side, safely behind Azure’s defenses, a second call to the payment gateway can be attempted using a higher-privileged access id. That more powerful credential, the one that can actually perform sales, remains safe and secure, on the server side, in the controller code shown in the second code sample.
The integrity of this arrangement is subtle but undeniably beautiful. On the client side, in the user’s browser, we can touch the sensitive credit card information directly, but the only payment gateway credential available there is limited to tokenization. On the server side, where we have credentials with the power to move real money, we have only a token to the sensitive credit card information and it is tied to the site owner’s merchant account. We can only move money between a single credit card and a single merchant. Neither side of the arrangement ever has enough information to make it worth breaking into. Only in the real time and instantly-transient synchronicity of both sides, is there an opportunity for commerce, and even then, it can only be between credit card holder and the merchant they intend to patronize.
Neither side provides a potential thief with anything worthy of stealing.
There are other reasons for splitting the activity as we have, but I don’t want to turn this article into an educational resource for hackers. As with so many security issues, attempts to warn the potential victims often have the side effect of educating the perpetrators. Discuss the issues with your payment gateway service provider before exposing more than is absolutely necessary, and even then, periodically review your security exposure for flaws.
Good Luck to everyone left in the Azure Challenge!
It has been a pleasure competing with and against you all!