Click here to Skip to main content
Click here to Skip to main content

PCI Compliant Credit Card Handling on Windows Azure

By , 2 Jun 2013
Rate this:
Please Sign up or sign in to vote.

Please note

This article is an entry in our Windows Azure Developer Challenge. Articles in this sub-section are not required to be full articles so care should be taken when voting. Create your free Azure Trial Account to Enter the Challenge.

 Introduction  

I started this article as an entry in the 2013 Azure Challenge, but changes in my schedule have lead me to drop out of the competition, leaving the article well short of its originally intended length and content.   This latest release of the article serves just to clean up its current offering; hopefully transforming it into a standalone article on the subject of PCI-compliant Payment Processing in Javascript.   The technique described is very applicable to Azure websites and other cloud service, but I never got to that integration.  I will try to get back here and augment this article as soon as my schedule clears. 

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. 

This article will demonstrate a client side technique for handling and persisting cardholder information without ever letting that information post back to Azure. Rather, JavaScript in the browser will post the sensitive information to a PCI Compliant data-vault, outside of the Azure network.  The data-vault will return a token in its reply, representing a contract between a single card holder and a single credit card merchant.  This token can only be used to move money between those two parties.  It contains no card holder or merchant account information itself, nor can it be used to access such information from the data vault.    By definition, sensitive information goes into the data-vault and never comes back; and the tokens which are returned are extremely limited in their capabilities.  From a PCI-compliance point of view, they are not considered sensitive information, so they can be touched by the Azure servers and stored in the Azure Database without compromising their transactions’ compliance. 

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.

Overview 

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. 

DISCLAIMERS

  • 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.

TECHNICAL SUMMARY

When the index view’s button is clicked, a JavaScript function first validates that information has been entered in the required fields, then cross-browser-posts that information to the payment gateway for storage and tokenization.  The gateway replies to the JavaScript, providing a transaction token which gets stored in a hidden field on the form.  The JavaScript then clears the credit card number and security code input fields from the form before submitting the form to its controller which is waiting on an azure webserver.  If the JavaScript had not cleared those input fields, we would now be in-scope on Azure, which would be a violation of PCI compliance.  Since the JavaScript did clear those fields, the sensitive information has been eliminated while it was still in the user’s browser, so all that Azure can see is the transaction token.  This means that our MVC controller, running on Azure, is out of scope. 

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)

The heart of this solution is the tokenization step and the heart of that step is the following JavaScript function.  This JavaScript is part of the index page of the azure website and gets called on-click of the button on the credit card collection form.

The highpoints of this JavaScript function include…

A). Validating the user input.  The payment gateway provides a JavaScript library which includes routines for validating credit card numbers, expiration dates, check routing numbers and assorted other payment processing information types.

B). That same javascript library contains a function called 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.

D). The ProcessTransaction() method also accept san additional parameter, a javascript “callback” function.  This function will be executed once the ProcessTransaction method completes and will be passed a reply object containing the payment processing results.  In this example, the callback function is being used to clear away the sensitive credit card information (E) and to store the transaction token and some other supporting information in hidden fields (F).  The last think the callback function attempts is to submit the form back to its controller using a small scrap of jquery (G).  (I tried to avoid using anything but the simplest JavaScript in this example, but I had trouble getting my non-jquery anonymous form submission code to work, so I replaced it.)

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.
Note: Although the payment gateway is nice enough to provide the same processing library in a bunch of different programming languages, each one is a little bit different.  For example, the request object for processTransaction() is a json array in javascript, but is a formally typed and instantiated class here in C#.    There is a little language specific style in each version of the library which I’ve used, but the underlying ideas remain consistent throughout. 

B). In the javascript call, we only loaded the username field, using a very low-privileged access token which was only empowered to run transtype ‘LOAD’.  We could have provided it with a more powerful username/password pair like we’re doing here, but it wouldn’t be a best practice.  I’ll describe why in the security section below.

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.

E). After 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. 

F). If 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

It might seem a little strange that we’re communicating with the payment gateway twice for a single transaction.  We’re calling the gateway once from clientside JavaScript, to tokenize the collected card information, but we’re not actually charging anything at that point.  Then, on the serverside, we’re performing the actual charge using the newly created token.   The reason for this extra work can be summed up in a single word, security.

EVERYTHING ON THE CLIENT SIDE IS VISIBLE: Look at the second line in section B of the JavaScript example.  That’s an access credential to the payment gateway, a key for submitting requests and doing business in a particular merchant’s name.  Go to the example website, right click anywhere and choose View Source.  You will find that exact same line, openly visible, exposed for the entire world to see.  As you look at the rest of that exposed source, you’ll find other exposed treasures such as the 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. 

Closing  

Good Luck to everyone left in the Azure Challenge!
It has been a pleasure competing with and against you all!

- Colt  

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

HTaylor
Software Developer (Senior)
United States United States
I've been programming in one form or another for more than 25 years, most recently in C# and MsSQL.
I'm co-organizer of the South Florida Windows 8 Developers Meetup Group which meets in Fort Lauderdale about once per month. I've got a mixed bag of professional programming experiences including a couple years in the payment processing industry and a couple decades in retail point of sale development.
I'm new to Azure but won't be for long.

Comments and Discussions

 
GeneralPCI Compliance Information Pinmemberbokohut22-May-13 8:59 
GeneralRe: PCI Compliance Information PinprofessionalHTaylor22-May-13 9:14 
GeneralRe: PCI Compliance Information Pinmemberbokohut22-May-13 21:50 
GeneralRe: PCI Compliance Information PinprofessionalHTaylor23-May-13 3:48 
GeneralMy vote of 5 Pinprofessionalroscler17-May-13 6:01 
GeneralRe: My vote of 5 PinprofessionalHTaylor17-May-13 6:15 
QuestionAccount Details PinprofessionalEnrique Albert16-May-13 13:42 
AnswerRe: Account Details PinprofessionalHTaylor16-May-13 17:03 
GeneralMy vote of 5 Pinmemberhsheldon3-May-13 4:31 
QuestionCould you expand on this? Pinmemberjkirkerx29-Apr-13 11:08 
AnswerRe: Could you expand on this? PinprofessionalHTaylor29-Apr-13 11:19 
GeneralMessage Removed Pinmemberjkirkerx29-Apr-13 12:39 
GeneralRe: Could you expand on this? [modified] PinprofessionalHTaylor29-Apr-13 17:18 
GeneralRe: Could you expand on this? Pinmemberjkirkerx30-Apr-13 6:35 
GeneralRe: Could you expand on this? PinprofessionalHTaylor30-Apr-13 6:48 
GeneralRe: Could you expand on this? Pinmemberjkirkerx30-Apr-13 8:32 
GeneralMy vote of 5 PinmemberBill Ross - Pax EDI29-Apr-13 9:58 
GeneralInteresting article. PinmemberDrABELL29-Apr-13 6:50 
QuestionPrevious Audit PinmemberBryan Tubbs29-Apr-13 5:35 
AnswerRe: Previous Audit PinprofessionalHTaylor29-Apr-13 6:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140415.2 | Last Updated 3 Jun 2013
Article Copyright 2013 by HTaylor
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid