12 replies [Last post]
solarian's picture
Offline
Bug FinderGetting busy with the Ubercode.
Joined: 04/20/2008
Juice: 113
Was this information Helpful?

I think there's a fairly serious gap in the recently-introduced cc number encryption, given that the server will be storing data (almost always on disk) for all active checkout sessions. This encrypted data can persist for uncompleted orders for as long as PHP retains its session data, which can be days or weeks. However, both the encrypted data and encryption key are stored with the same open access levels (these files are almost always world-readable -- PHP creates them that way -- at least on Apache).

Although offering a slight level of security over session ID leakage, that form of attack was never the real issue when storing cc numbers in sessions. An attacker with any level of filesystem access (e.g., by exploiting another Drupal module or poor permissions on shared access servers) to gain access to both the session data and the encryption key, giving access to the cc numbers & billing details of all the uncompleted orders sitting on the server. This changes the position of Ubercart for PCI DSS compliance; and given that it's very easy to sniff for Ubercart sites (the footer messages give it away), it's not infeasible that Ubercart store owners could be targeted.

In the short term, to mitigate somewhat against these kind of attack, the uc_credit.key file should certainly be chmodded to 0600 when created, although this would only protect against some shared-server attacks and not against vulnerabilities in Drupal and other modules.

A PCI DSS compliant level of protection could be offered by not storing the cc number in a session, but simply propagating it via POST on cart/checkout and cart/checkout/review; and (if the user selects this option) when storing the cc number in the database after checkout, by encrypting it against a user-entered admin password (which would *not* be stored permanently on the server). The following proposal also has the advantage of protecting against a wide variety of attacks except alterations to the executing code or a specific admin-user directed client-side attack.

My idea for how this would work is detailed below:

*Setting up the encryption*
The admin user enters his special password, at which point all current db entries are re-encrypted with this key combined with the file-based encryption key to encrypt the cc data in the db. The password is not stored in a session, and thus never leaves POST. The database can be re-encrypted whenever the password expires -- and there should at least be an option for enforced expiry.

*Retrieving cc numbers from the db in admin/store/orders*
1) Admin user enters password when prompted.
2) Half of the admin password is stored in a time-limited db session (cleared using a small cleanup routine in hook_cron), the other half is stored in a client-side cookie and thus is never accessible anywhere on disk (unless the user is logging POST data, in which case cc numbers would already be available in plaintext). This allows the admin to browse through several orders with cc details without having to repeatedly enter the password -- this would only cause the user to be less careful about guarding their password.
3) Whenever the card number is retrieved from the database, both halves of the special admin password along with the key in uc_credit.key are combined to decrypt the number.
4) A log is retained of the Drupal user who has viewed the card number in order to satisfy the PCI DSS.

(A slightly better form of (2) is possible if the second half of the password were stored in a cookie using JS on the client side and never sent to the server. None of this would be able to keep out a good XSS or keylogger attack, but that is beyond what PCI DSS deals with.)

Obviously, HTTPS needs to be used on admin/store/orders (at the very least) in order for this to work. HTTPS should also be configured for cart/checkout, and in my view cc numbers should only be enterable or retrievable via https, unless in some kind of debug mode because otherwise a non tech-savvy store owner could leave themselves wide open without realising (and in my experience, they will always do this if given the opportunity, therefore default permissions should always be restrictive).

Ryan's picture
Offline
Joined: 08/07/2007
Juice: 15476
Re: PCI DSS session handling & encryption

I'd like to run three things by you for feedback that might help clear things up.

  1. Drupal has its own session handlers so that session data is stored in the database. As far as I know, this means you won't find session data in file directories anywhere. So, someone would have to access a non-public directory to get the encryption key and then won't find any session info to play with in your tmp directories.
  2. Drupal's forms API prevents only storing the info in $_POST. When a user submits a form, Drupal processes the page request which includes building and processing the form... and then it redirects once the form has been processed. This means I can't access data in $_POST when building the review page, because no data is being posted over. I couldn't find any way around this, which led me to do what I'm doing. The current system stores the encrypted CC data in a session variable for the duration of that redirect... and for that duration only. This means CC data isn't hanging around indefinitely, even for orders that get abandoned in checkout. I had to do a bit of magic to cache this data from the session variable and stick it in a hidden value on the form. I honestly don't know any way to make the system more secure than this given the limitation placed on us by the Forms API. (btw, I believe the redirect is there intentionally to prevent multiple form submissions.)
  3. The language of the PCI DSS states that you cannot store the sensitive card information post-authorization. I'm all for meeting the spirit of the law and not just the letter, but that uber-short period of time between the processing of the checkout form and the redirect to the review form happens before the card is authorized. We don't even know if it's a real, workable card. So from what I can tell, we're PCI compliant here.

I think there are security risks inherent in doing any e-commerce... the only way to make checkout more secure would be to only accept checks and wait for them to clear. Sticking out tongue If someone is worried that the core offering isn't strict enough, I guess I'd recommend a redirected service like PayPal WPS or 2Checkout.com, both of which ship w/ Ubercart.

solarian's picture
Offline
Bug FinderGetting busy with the Ubercode.
Joined: 04/20/2008
Juice: 113
Re: Re: PCI DSS session handling & encryption

Oh dear, how silly of me -- yes, I see you're right that sessions are stored in the "sessions" table. I actually read about this in the Drupal book, but my memory clearly ain't up to much. I'm so glad I'm using an alias! Apologies for that -- I must seem like a right pain in the proverbial. The information you give does seem to put things in a better light, but unfortunately I don't think it materially affects things.

The central points that I'm making are as follows, when modified to incorporate your comments:

  1. Abandoned orders still contain encrypted cc details in uc_orders. This conflicts with PA DSS points 1.1.5 and (most importantly) 9.
  2. The encryption offers nothing more than fig-leaf security, because anyone gaining access to the db ciphertext (either uc_orders or uc_payment_credit) can also access the encryption key, on account of the fact that Drupal allows insertion of PHP code into content that it reads from the db. One could simply use SQL to inject some PHP code into a node so that viewing that node will invoke your own decryption method and output the contents of all cc details from the db. This conflicts with PA DSS points 2.3-2.7.

There is only one way, I think, to deal with the problem of cc details in abandoned orders. It does seem possible to propagate the cc details via POST, because both $_POST data and $form_values are available in the uc_cart_checkout_form_submit() function. Rather than redirecting the cart/checkout/review, the review form could be built from there. Additionally, Ubercart will -- I suppose -- not be DSS compliant unless it demands an encrypted connection in checkout. The following test could be used:

$https = ($_SERVER['HTTPS']!='off' && $_SERVER['HTTPS']!='') ? true : false;

I don't think Ubercart will be able to comply with the PA DSS requirements for encryption (the key must be stored in a manner that would be impossible on any normal setup), and so in my view it's much better not to try to implement it. Besides, there's no need to do so unless you store cardholder data.

(PA DSS reference: https://www.pcisecuritystandards.org/pdfs/pci_pa-dss_security_audit_proc...)

Ryan's picture
Offline
Joined: 08/07/2007
Juice: 15476
Re: Re: Re: PCI DSS session handling & encryption

My general thought is that you're going to have bigger problems from someone hacking your database, no matter how secure the system is. That aside, I still don't see why you're assuming that CC data is being stored for abandoned orders. The only CC data stored in the orders table is the last 4 digits of the card number unless you're running in debug mode (which states that it may lead to PCI compliance issues). Also, uc_payment_credit is deprecated. It's no longer used, but I had to leave it in for folks updating from past versions.

So... the encryption is used to store either the last 4 digits of the PAN in the order's data array and an encrypted hidden field on the review order form that can be decrypted server side to get the card number... but unless a hacker manages to beat someone up while they're performing checkout to get that encrypted string... I just don't know how they can get to the data.

You are correct in that full PCI compliance will require SSL, and I need to update the documentation to make sure that's explicit.

And I don't mind the scrutiny. I want Ubercart to be as secure as possible.

solarian's picture
Offline
Bug FinderGetting busy with the Ubercode.
Joined: 04/20/2008
Juice: 113
Re: Re: Re: Re: PCI DSS session handling & encryption

Thanks for clearing that up -- I saw the encrypted data in the uc_orders table and assumed it must be the whole card number. My mistake.

Also am glad you're OK with my trying to pick holes like this! I still think Ubercart is a great shopping cart. Smiling

However, I still think storing the session data on db/disk even for a short time is a DSS fail. It could be exploited using a MySQL trigger, then decrypted and even emailed by hooking into Drupal, and all that would be required is an SQL injection somewhere. I appreciate that a db hack of this type would create other problems, but I don't believe it could create much bigger problems than potentially making one liable for £100,000 (as it is in this country) to your cc merchant service! Nobody would even want to hack your db unless they thought you were storing cc data, so if it never gets into the db then it puts off the script kiddies.

Nevertheless, if this session storage could be eliminated there would still be potential holes -- after all, someone could potentially inject code into uc_credit.module to extract and email POST data; but that can be dealt with using chattr +i, which would then lock down cc data so it could only be gotten at through an Apache exploit or with root access.

popthestack's picture
Offline
Joined: 05/15/2008
Juice: 22
Ryan wrote: The language of
Ryan wrote:
  1. The language of the PCI DSS states that you cannot store the sensitive card information post-authorization.

Actually, that's not true.

The attached png file is a screenshot of the table found on page 3 of the PCI DSS specifications PDF that can be found here: https://www.pcisecuritystandards.org/tech/

As you can see from the table, it is perfectly OK to store the credit card number (PAN), card holder name, service code, and expiration date as long as it's securely encrypted.

What is not OK to store after an order has been made is the sensitive authentication data (full magnetic stripe, CVV2, and PIN).

More information on store protecting cardholder data is on page 6 of the document and again states that only the sensitive authentication data cannot be stored. The credit card number can be stored.

This can and should be corrected in Ubercart. I'm willing to help out if someone will point me in the right direction.

AttachmentSize
pci-dss-storage.png 62.92 KB
Ryan's picture
Offline
Joined: 08/07/2007
Juice: 15476
Re: Ryan wrote: The language of

I don't think you contradicted me. Smiling I didn't use the exact language, but it was the "Sensitive Authentication Data" that I was referring to when I said "sensitive card information."

So, at present, there's nothing to correct. It functions as you described.

popthestack's picture
Offline
Joined: 05/15/2008
Juice: 22
Re: Re: Ryan wrote: The language of

Holy crap that was a fast reply. haha

So is this text incorrect on the Credit Card Settings page (emphasis added)?
http://www.ubercart.org/docs/user/2731/credit_card_settings

Quote:

As of Ubercart 1.0 RC 5, there is also a credit card debug mode that you can use when testing or to store encrypted card data with orders for offline processing. This may open you up to vulnerabilities, but you should be aware that even in debug mode Ubercart will truncate credit card numbers to the last 4 digits when a card gets processed. This is in accordance with the PCI DSS restriction that full card numbers and expiration dates should not be stored locally after a card has been authorized/charged.

Ryan's picture
Offline
Joined: 08/07/2007
Juice: 15476
Re: Re: Re: Ryan wrote: The language of

I see what you're saying. Yeah, that text can be updated, and I'd be happy to review a rewording. I guess the main concern is that most folks won't meet all the other security requirements or have a need to bother with saving CC numbers/dates post payment anyways. Sticking out tongue

Ageimp's picture
Offline
Joined: 12/15/2008
Juice: 15
Re: Re: Re: Re: Ryan wrote: The language of

Hi, I'm a newbie here (and not a coder sorry). Just getting our Coffee / Ubercart store compliant with our selected Payment Gateway. They require a PCI DSS certificate of compliance from Ubercart.
Excuse my ignorance but is this something i can get/download or find anywhere here?
Thanks for your help.
Adrian (New Zealand)

Ryan's picture
Offline
Joined: 08/07/2007
Juice: 15476
Re: Re: Re: Re: Re: Ryan wrote: The language of

Never heard of it, though I can make up a certificate if it will suffice. If it's something they want us to pay for... well... I'm not sure how soon that would happen. Sticking out tongue

If printing this comment suffices, we're compliant out of the box.

Ageimp's picture
Offline
Joined: 12/15/2008
Juice: 15
Re: Re: Re: Re: Re: Re: Ryan wrote: The language of

Should be enough. Thanks!

tedmarks's picture
Offline
Joined: 07/29/2009
Juice: 4
Re: PCI DSS session handling & encryption

Data Loss Prevention can be used here, thses are usually dedicated hardware/software platforms, typically installed on the organization's internet network connection, that analyze network traffic to search for unauthorized information transmissions, including email, IM, FTP, HTTP, and HTTPS (called data in motion). They have the advantage that they are simple to install, and provide a relatively low cost of ownership. They will be proved helpful and the best for PCI DSS compliance.