How secure are Indian payment gateways?

India has a dearth of good payment gateways – most have obsolete difficult-to-use APIs requiring days, if not weeks, to integrate. They require at least a dozen documents (most of them need them sent through post) before they even let you inside their walled garden. Additionally, gateways have complicated plans – depending on your initial spending budget you can get a deal for 3% or otherwise end up paying 5%. Of course, you can also haggle. Above that most of them have a monthly/yearly maintenance fee. It’s a sad state of affairs – and part of the reason is because of the government policies making it very difficult to accept payments easily.

I was very excited when Flipkart’s Payzippy launched recently. (NB: I wrote this post a while ago, but I waited while I contacted the gateways about the security issues before publishing). As I was skimming through their API document, I discovered they were using MD5 which is not considered cryptographically secure anymore. I looked deeper and found a few other security measures which, as a payment gateway, they should have taken. When I looked at other payment gateways, they had similar problems (some even much worse) and so I compiled a list of Indian payment gateways I could find and research about.

First, some layman technical info.

How payment gateways work

Indian payment gateways are asynchronous; the user is first redirected to the gateway where he/she enters his/her card details, and then redirected to the mandatory 3-D Secure/Securecode password verification. These redirects happen through the user’s browser. To verify that a transaction received by the gateway is associated with the right user and originated from the merchant – the merchant attaches a message authentication code (MAC) of the transaction which is transmitted to the gateway along with the transaction details. The MAC generation algorithm is gateway specific. Gateway at its own end will recompute and verify the MAC to make sure data hasn’t been tampered with and then proceeds with assessing the rest of the transaction. After it verifies the transaction it redirects back to the merchant with the status of the transaction and the MAC of the status so the merchant can verify the request originated from the gateway. These “handshakes” should be tamper proof, or bad things can happen.

Not following along? Here’s a drawing to help you understand:

Message Authentication Code Flow

Message Authentication Code

The sender (merchant) has a secret key (shared with the gateway) and uses a predetermined MAC algorithm to generate a MAC string which is included in a hidden form field while redirecting him/her to the receiver (gateway).

A bit about hashes

Why are MACs needed? They are used to ensure data integrity during redirects. MACs need to be tamper proof – otherwise a user could change the transaction amount in transit from merchant to gateway, or modify a failed transaction to look like a successful one. A naïve approach to implementing simple MACs is to use a common hashing algorithm (like SHA1 or MD5) with a shared secret key which is then appended to the data transmitted.

# Method 1: Key as a suffix
mac = hash(message + key)

# Method 2: Key as a prefix
mac = hash(key + message)

Both these approaches have flaws:

  1. When using key as a suffix with a collision prone hash algorithm like MD5 an attacker may modify the message in such a way that the MAC doesn’t change.
  2. When using key as a prefix (in addition to the previous vulnerability) an attacker could use length extension attack to add more information to the message.

MACs like these depend on the collision resistance of the underlying hashing algorithm for security. One right way to preserve and validate integrity is to use HMAC which uses a nested hash calculation to make the hashes tamper proof. HMACs are meant for verifying integrity; using a hash function isn’t.

Security best practices

I chose a few selected security practices which can result in possibly serious vulnerabilities. Of course, this is not an exhaustive list.

Merchant login page shouldn’t be on HTTP

Serving login pages over HTTP is insecure; it’d be trivial to redirect user to a fake login page, or modify the page in transit and give user a modified form to submit data to.

Use HSTS

Using the HTTP Strict Transport Security (HSTS) header a site can tell the browser to always use HTTPS for that domain in the future. None of the gateways I researched were using HSTS. Most of them are using 301 redirects which are stored in the browser cache. But 301 redirects are URL specific, while HSTS is domain specific. i.e. 301 redirects a single page, HSTS redirects a complete domain. With HSTS (after the first visit by a user) the browser will never contact the site using HTTP again on any of the site pages. If a site isn’t using HSTS, the user cookies can be stolen by directing the user to visit a non HTTPS page while logged in or by redirecting them to a modified login page.

Secure cookies

Cookies should be marked Secure, which tells the browser to transmit the cookie only when the request is HTTPS. So, even if a user opens an HTTP page (which shouldn’t exist), their cookie is never transmitted in clear text to the server. If the secure parameter doesn’t exist, an attacker could eavesdrop on a user’s session when an HTTP page is opened. Having access to the merchant’s cookie, the attacker could steal user data, reset keys or even worse.

Hash based authentication

I explained MACs earlier in the post. While the above-mentioned security practices involve a malicious third party, this one just involves a malicious user. If a gateway is using a weak MAC generation algorithm, a user could spoof a request with a “transaction succeeded” message which will tell the merchant that the user has paid.

Not relying on “security through obscurity”

Security through obscurity may work in some cases, but it does not work in case of payment gateways at all. Firstly, this information (handshake algorithm, for example) is available through other means (eg: through e-commerce software code) and secondly, merchants, both existing and past, using the gateway have that information already.

Payment gateways tested

I included the following payment gateways in my research. Gateways are rated on a scale of 1 to 10. If any payment gateway is missing, leave the name and links in comments and I’ll update the post with my observations. Click on a gateway to directly jump to its review.

EBS
Payu
CCAvenue
Zaakpay
Direcpay
Transecute
Payzippy

Citruspay (Added on 2013/10/02)
Juspay (Added on 2013/10/22)

I tried to contact the gateways about the critical issues over three weeks before publishing this post. I sent a generic email because none of them had specialized email for reporting security issues. However, none of them replied to my later emails regarding their plans on fixing these issues. Clearly, the one who didn’t reply at all don’t care about user security at all, but the others didn’t fare well either.

Observations

The following observations are based on what information I could find – I do not have an account to login and play around with any of them (test accounts are only available to customers). Even their documentation is a closely guarded secret. Thanks to search engines, I found API documentation or integration code for most of them, which I used to figure out how the communication between merchant and gateways was going on.

EBS

The home page of EBS loads unencrypted over HTTP. Their login page is hosted on secure.ebs.in, but it’s also available on HTTP. Cookies are marked secure. HSTS is not implemented.

EBS uses MD5 with hash(key | message), and calls it “secure hash method”, which is really not secure at all. A length extension attack is not effective here though, because the messages have a fixed data structure with separators.

Hash = MD5(secretKey|account_id|amount|reference_no|return_url|mode)

This hash is embedded in HTML form. While redirecting back to the merchant, EBS uses the same key to encrypt data with RC4.

Let’s talk about RC4 first – RC4 is a stream cipher. Stream ciphers create a pseudorandom stream, called keystring, based on the key. This keystring is bitwise XORed with the plain text to generate the ciphertext (and if XORed with the ciphertext gives back the plaintext because of the way XOR works). Stream ciphers have one very important requirement – the same key should never be used twice to encrypt messages.

RC4 is also susceptible to bit flipping attacks. For example, EBS redirects back to merchant with a string containing “0” or “1” depending on whether a transaction succeeded. Even if a transaction fails at EBS’s end the user can just flip a bit to change 0 to 1 and the merchant will receive the transaction as valid. If you had to take away one thing from this post, remember this – “Encryption is not authentication“.

EBS’s implementation of RC4 is also broken. RC4 has weak encryption for the initial part of keystream. It’s recommended that the first few thousand characters be discarded to prevent leaking the key. But EBS encrypts the message without discarding any part of the keystream.

Lastly, this whole message encryption is an optional feature which is disabled by default.

To sum up, possible vulnerabilities in EBS:

  • Secret key can be cracked easily, or a transaction state can be modified
  • Spoofing gateway responses and requests
  • Redirect user to a fake login page.

Source: Integration manual (the manual is in the zip), “Secure hash validation manual

Gateway response: Only initial response, no follow up from their end.

Grade: 1/10

Payu

Payu redirects user to the secure site after which all connections and links are encrypted. Login page is not available over HTTP. Payu doesn’t use 301 redirects. Every time a user opens payu.in, HTTP page is loaded first. No HSTS implemented. Cookies are marked secure.

PayU uses trivial MACs – SHA512 (key | message | salt) which has no known collisions. Although it’s quite likely in the future. Their hash exchange protocol is also resistant to length extension attack – during communication the hashes are computed for the message in normal and reverse order.

Possible vulnerabilities:

  • Redirect user to a tampered login page.
  • MAC is secure for now but needs to be future-proofed

Note: After I published this post, a PayU engineer replied and said that verifying a transaction is a necessary requirement for merchants who provide services before receiving funds.

Grade: 8/10

Source: Integration document

CCAvenue

Home page opens on HTTP. Login page also links to HTTP which then redirects to SSL page. A fake login page can be presented. Luckily, cookies are marked secure so at least existing sessions are safe from sniffing. No HSTS is implemented.

CCAvenue uses Adler checksum – before writing this I had never even heard of it. Adler is an ancient checksum based on the sum of ASCII values in a string. The callback from gateway to merchant uses Adler again making a request easily tamperable. The return request has a character Y or N pointing to if the transaction succeeded among other details. Changing N to Y is simple – use the difference of (Y – N) and modify the checksum.

After I contacted CCAvenue, they told me that they do not use Adler32 anymore and instead use encryption. I couldn’t find any information about their new protocol, but “encryption is not authentication”.

Possible vulnerabilities:

  • Spoofing gateway responses and requests
  • Redirect user to fake login page

CCAvenue already has a poor track record in security – they were broken into in 2011 with an SQL injection.

Grade: 1/10

Gateway response: Migrated away from Adler32

Source: Integration document, Sample implementation

Zaakpay

Zaakpay redirects to secure page with a 301 redirect, but no HSTS here either. Cookies are marked secure. Zaakpay is the only gateway I researched which uses HMAC for verification. And is the only gateway to not have a “secret integration document” available only to customers.

Possible vulnerabilities:

  • Redirect merchant to a spoof site on first load

Grade: 9/10

Source: API documentation (with sample codes)

Direcpay

Login form exists on the home page which is served on HTTP which then submits to a HTTPS . Cookies are not marked secure. No HSTS.

And you thought CCAvenue using Adler was bad? For encryption/decryption – ahem – DirecPay uses doubly encoded Base64. As if doing it twice makes it any more secure. Let me quote from their verbiage (in their documentation):

Transaction parameters will be accepted from the merchant website in an encoded format to ensure that no data is tampered and transaction is processed in a secured fashion.
The script for encryption / decryption logic of transaction parameters can be downloaded from the link:
http://www.timesofmoney.com/direcpay/downloads/dpEncodeRequest.zip

I wouldn’t put it past them to be unable to stop basic SQL injections.

Well, I’ll assume there’s no authentication.

(Note added on 2013-10-11: Direcpay’s response on using Base64 is that they have been migrating their customers to an API with encrypted communication since December 2012, however not all the merchants have moved yet. Newer merchants will use the new API. Nevertheless, my view on this is that using encryption may be better than Base64, but it’s still not the most secure way of doing things.)

Possible vulnerabilities:

  • Redirect users to a spoofed login page
  • Sniff already logged in user cookies.
  • Free for all – spoof gateway responses and requests

Incidentally, Google India uses DirecPay for AdWords but they get to use a special API which uses PGP for communication. Indiatimes Shopping (DirecPay is owned by Times group) also gets a special API which uses something completely different.

Grade: 0/10 (Remember this is on a scale of 1 to 10)

Gateway response: None

Source: Integration document

Transecute

Transecute login loads over HTTPS directly on a different domain (secure.transecute.com). HTTP is inaccessible (404) on that domain. No HSTS is implemented. At least cookies are marked secure.

I couldn’t find Transecute’s integration document. I found an Opencart forum post with their integration code in PHP according to which it uses MD5 with (message|key)

Possible vulnerabilities:

  • Modify text such that MAC hash remains same
  • Redirect users to a fake login page during initial load

Grade: 6.5/10

Gateway response: No follow up after initial response

Source: Integration code (archive link), Opencart forum post with same code

PayZippy

The newest kid on the block. At least it’s well designed. HSTS is not implemented. Home page redirects from HTTP to HTTPS. Cookies are not marked secure so cookies can be sniffed the first time user opens the HTTP page.
Hash is complicated in PayZippy’s case – it’s up to the user to choose either MD5 and SHA1, but it’s still MAC(message | key), which can be tampered with. Their (official?) Magento extension is also using MD5 by default.

Possible vulnerabilities:

  • Modify text such that MAC hash remains same
  • Redirect users to a fake login page during initial load

Grade: 6.5/10

Gateway response: No follow up after initial response

Source: Magento integration, Integration document received in email

Citruspay

Login page is served over HTTP, which submits to HTTPS. Cookies are marked secure. No HSTS.

CitrusPay is the second gateway which uses HMAC for verification.

Possible vulnerabilities:

  • Redirect user to a fake home page

Grade: 7.5/10

Source: Integration document, Sample integration code

JusPay

The homepage of JusPay opens on HTTP, with no redirects. The merchant site is a subdomain (merchant.juspay.in) linked on the home page. It’ll redirect to HTTPS, but there are no 301 redirects. Cookies are tagged secure.

JusPay has 2 solutions for acccepting payments:

  • IFrame checkout –  a JusPay page is displayed in a frame at the merchant’s site and the user can enter their details.
  • Inline checkout – The user enters the credit card details on the merchant’s site itself

Both are different from how other gateways are doing things. The CC details are input on the merchant site directly. In the IFrame, the data goes directly to JusPay, and in Inline the data goes to merchant’s server which then communicates to JusPay (server to server). I hope they have a strict requirement of HTTPS on merchant checkout pages.

JusPay is not using any MAC. That works for inline checkout because their communication happens server to server, i.e. the user can’t tamper with the traffic. On return from JusPay, payment status verification is mandatory, which should provide security for IFrame. But none of their integration handled that verification, it’s up to the merchant write that piece of code. It might be an issue if the merchant just checks the final status of the transaction and doesn’t check the amount and other details, which could have been tampered with.

Possible vulnerabilities:

  • Redirect user to a fake home page.
  • IFrame option might have issues depending on how the merchant handles the payment reconciliation.

Grade: 6.5/10

Source: Demos on their merchant site, integration code

Conclusion

I didn’t grade on some things – XSS, CSRF, iframe embedding, vulnerable software, server misconfiguration – you get the idea. Those are, in many cases, result of bugs. Bad design decisions aren’t bugs though. Overall this post should give a good idea if you are looking for a payment gateway to choose from. It’s great that Zaakpay is doing many things right. Now only if they could redesign their UI.

None of the gateways use HSTS – which I consider a huge security issue in some of them when coupled with other issues. HSTS is not perfect – there’s the first page load which can still be tampered with, but it’s better than 301 redirects and infinitely better than serving all pages on an insecure channel. And it’s not at all complicated to set up.

MD5 is the favourite method among many gateways – Transecute, PayZippy and EBS use it. It’s surprising that developers still believe that MD5 for something this important and sensitive is appropriate.

PCI-DSS is useless. Every gateway has PCI DSS certification when they are clearly not secured at all. PCI-DSS deals with how credit card data is handled – which they might be adhering to. But when it comes to handling transactions PCI-DSS says nothing about that.

What I found disappointing was that the gateways (except Zaakpay and to a lesser extent Payu) do not seem to be taking security seriously and have not been upfront about these flaws to their customers. Security should be a priority, rather than an afterthought. Bad security choices made consciously while designing the system encourage bad security practices throughout the rest of the system. Furthermore, by keeping their security practices unpublished, they have avoided the kind of public scrutiny which could have caught these design flaws long ago.

Epilogue

Before I wrap up, timing attacks are worth a mention – since all gateways are using MACs some way or the other, all of them are vulnerable to timing attacks. None of the integration code I read had special protection against these. A timing attack works on information leaked by lazy comparison between two strings. Consider these two comparisons for example:

# Comparison 1
python -m timeit '"abcd" == "abce"'
10000000 loops, best of 3: 0.0329 usec per loop

# Comparison 2
python -m timeit '"abcd" == "qwer"'
10000000 loops, best of 3: 0.0293 usec per loop

Note the time difference between comparison 1 and 2. Using this time difference it’s not difficult to compute the right hash (without knowing the key at all) one character at a time. It’s not practical in many cases because there’s too much noise – but if a merchant is running a site on a shared host things become quite a bit easier. The search range is very small – there are only 16 hexadecimal characters. If you are a merchant with a gateway using MACs – make sure to use a comparison function which doesn’t do lazy comparison.

Disclaimer: This post is for informative purposes only. I don’t condone the use of any of the vulnerabilities highlighted here for any unlawful use.