Payment application based on NTAG213 vs. Ultralight C (using Android NFC) - security

I have a (university) project where I basically write and read text out of an NFC tag with Android devices in order to store one's balance in the card (which can be used on the cafeteria, for example).
Right now, I'm using NTAG213 doing the below code:
ndef.connect();
NdefRecord mimeRecord = NdefRecord.createMime("text/plain", messageEncrypted.getBytes(Charset.forName("US-ASCII")));
ndef.writeNdefMessage(new NdefMessage(mimeRecord));
ndef.close();
As you can notice, I'm using application level encryption to encrypt the message (messageEncrypted) before writing it to the tag (AES-256 encrypt with 'com.scottyab:aescrypt:0.0.1' library - with a very big password key that uses also the tag UID as part of it).
So far so good - only I can understand the data on the tag.
On my research, I've found that when it comes to security Ultralight C > NTAG213.
Question 1) When using application level encryption, why (is it?) is MIFARE Ultralight C safer then NTAG213?
Question 2) I'm pretty sure I can guarantee security using AES encryption, but I don't want people (besides me) messing with the stored data (formatting tag or writing info there). I see that the only way of preventing that (please, correct me if I'm wrong) is to set a password for the tag. However, both NTAG213 and Ultralight C have only an 32-bit password. Is it good enough? Is there another way of preventing someone (besides me) writing data?
Question 3) Which other security measures can I use on such tags to enforce security (tag and application layer)?
Question 4) When you compare tag security (MIFARE DESFire > Ultralight > NTAG213 > MIFARE Classic), what is really being compared? The ease of one cracking the (native tag's) encryption or the ease of one store (anything) on the tag without permission?
Question 5) I see a bunch of other techs (MIFARE DESFire, ICODE SLIX, Infineon Cipurse) that are more secure, which makes me wonder if the tech I'm using (NTAG213 or Ultralight C) is good enough for storing someones balance. Would you (and that's a personal opinion) say that NTAG213 with application level encryption and 32-bit password good enough for this type of application? And how long would it take someone to actually break its security?

When using application level encryption, why is Ultralight C safer then NTAG213? Is that even true?
First of all, "safer" depends on what your actual protection goals are. Since you want to store a balance (cash money!) on the card, you would probably want to (at least) protect towards the following goals:
Users must not be able to print their own money by setting an arbitrary balance on their card.
Users must not be able to duplicate their card and, consequently, their money balance.
Users must not be able to print their own money by restoring (roll-back) their card to a previous balance after payment.
Users must not be able to print their own money by replaying a top-up procedure.
Users must not be able to evade payment by tearing their card during a payment transaction.
Users must not be able to generate an arbitrary (and potentially higher) balance on their card by tearing their card during a top-up procedure.
In addition, you might not want to trust operators (the persons accepting payments and performing top-up) as well. In a system where one group of operators performs only top-up and the other performs only payment transactions, the latter group should probably not be allowed to ever "create" money. Particularly, you have to make yourself very clear about whether you fully trust the (Android) devices that you use in the field to perform these operations and whether you trust operators (e.g. that they don't perform any attacks against these devices).
Moreover, there might be privacy aspects that you need to consider (e.g. if the balance is freely readable, if users are identifiable, etc.)
So let's look into what you "application level encryption" adds in terms of security:
Since users do not know the encryption key, they are probably not able to generate an arbitrary balance on their card. However, this heavily depends on the format of your balance (in unencrypted form). Users can make arbitrary modifications to the cipher text with result in "random" modifications of the plain text. Consequently, users may be able to modify the balance value despite encryption. Digital signature/message authentication codes are they path that you would probably want to take to overcome this.
Since the encryption key (assuming encryption would be sufficient, which it probably is not) depends on the UID of the tag, you may be safe against cloning of cards (+ balance). However, be aware that the UID is just a freely readable identifier. It is by no means authenticated itself and may be clonable as well. See Serials on NFC Tags - truly unique? cloneable?.
The encrypted value does not protect you from users restoring their balance to a previously recorded value after payment. This type of vulnerability has been found before (particularly in MIFARE Ultralight based systems), see, for instance, Benninger, C., Sobell, M. (2012): NFC for free rides and rooms (on your phone). In: Presentation at EUSecWest 2012.
Since you write the complete value during a top-up procedure (i.e. there is no specific "increment balance" command), you are probably safe against users replaying a top-up (except for the roll-back aspect of this).
Effects of tearing are probably rather limited if your system only allows for attended payment/top-up.
So let's see what additional features NTAG213 would have that you could use to secure your system:
UID is unique on genuine tags. This does not help much, see Serials on NFC Tags - truly unique? cloneable?.
Originality signature: same as above, the originality signature is also just a static, freely readable value. Consequently, it's just as well susceptible to cloning.
The one-way counter might be a tool to help you in protecting against roll-back (by including the counter value into the signature). This still would not prevent cloning onto a tag platform that allows to generate arbitrary counter values. Moreover, the counter is not easily controllable and will change its value if the user tries to read the tag. Consequently, it's questionable if an implementation based on that value would be reliable.
Unlike MIFARE Ultralight, NTAG213 does not have a usable one-time programmable area (since that's already used by the capability container). Consequently, you can't implement a one-time deductible balance based on that.
The password protection feature could help you in authenticating tags (by performing password verification) and in protecting the value stored on the tag (by making the value only readable/writable after password verification). However, the password is transmitted in clear text (may be subject to sniffing, particularly in (but not limited to) unattended scenarios) and there is no cryptographic binding between the password and the actual read/write.
MIFARE Ultralight C would add the following:
The OTP bytes can be used. If it's an option to make the tags one-time usable (i.e. they start with a specific balance that can only be deducted from and not topped-up), then using the OTP bytes to represent the balance would be an option. Note that there's still lots of things that you could do wrong with that, e.g. Beccaro, M., Collura, M. (2013): OTP circumventing in MIFARE ULTRALIGHT: Who says free rides?. In: Presentation at DEFCON 21
The authentication is much improved. The 3DES authentication scheme seems to be sufficiently secure to prevent sniffing the key. However, read/write commands are also not cryptographically bound to the authentication step. Consequently, an attacker might be able to let a genuine payment terminal + genuine tag perform authentication, but redirect read/write to somewhere else. This might (particularly) be a problem in an unattended scenario.
I'm pretty sure I can guarantee security using AES encryption.
See above. This is probably not true.
I don't want people messing with the stored data. I see that the only way of preventing that is to set a password for the tag.
A password/authentication key may help, but be aware of the limitations due to authentication being decoupled from read/write on these tag platforms.
Both NTAG213 and Ultralight C have only a 32-bit password.
This is not true. NTAG213 has a 32-bit password. MIFARE Ultralight C uses a more sophisticated mutual 2K-3DES authentication mechanism with a 112-bit key.
When you compare tag security, what is really being compared?
Authentication mechanisms (algorithms, key sizes)
Communication security (e.g. is the communication itself encrypted/authenticated using a session key derived from the authentication step?)
Access control (e.g. are there separate keys for top-up and payment?)
Are there dedicated mechanisms for balance management (e.g. value fields, dedicated increment/decrement operations)? And, consequently, are ther mechanisms to protect agains tearing attacks?
And probably more ...
I see a bunch of other techs that are more secure, which makes me wonder if the tech I'm using is good enough for storing someones balance.
You specific system is flawed in many ways. In my opinion MIFARE Ultralight/NTAG203/NTAG21x are definitely not a good choice for a an offline system storing cash money on the cards.
MIFARE Ultralight C may be suitable with some precautions. I would definitely refrain from using that in unattended scenarios, and I would probably use an online system tracking the balance and monitoring for inconsistencies.
Anything that uses symmetric cryptography and storing the cryptographic keys in a terminal would certainly require precautions against malicious operators. It's probably fairly easy for an operator (with some knowledge) to extract keys from an app and generate their own money.

I guess your question is too broad and not for all subquestions this section of SO is the most appropriate one.
By focusing on cryptographic strength you miss something: if the low level security of the token can be easily attacked, nobody needs to crack your key.
A simple dump and later restore (after some payments) corresponds to printing money
If the token contains the money directly (instead of only identifying the wallet, which is stored on a background system), you need a far more secure system to avoid financial damage. This involves dynamically encrypted communication but continues with substantial further topics.

Related

UUID on database level used as a security measure instead of a true rights control?

Can UUID on database level be used as a security measure instead of a true rights control?
Consider a web application where all servlets implements "normal" access control by having a session id connected to the user calling it (through the web client). All users are therefore authenticated.
The next level of security needed is if a authenticated user actually "owns" the data being changed. In a web application this could for example be editing some text in a form. The client makes sure a user, by accident, doesn’t do something wrong (JavaScript). The issue is of course is that any number of network tools could easily repeat the call made by the browser and, by only changing the ID, edit a different row in the database table behind the servlet that the user does not "own".
My question is if it would be sufficient to use UUID's as keys in the database table and thereby making it practically impossible to guess a valid ID (https://en.wikipedia.org/wiki/Universally_unique_identifier#Random_UUID_probability_of_duplicates)? As far as I know similar approaches is used in Google Photos (http://www.theverge.com/2015/6/23/8830977/google-photos-security-public-url-privacy-protected) but I'm not sure it is 100% comparable.
Another option is off cause to have every servlet verify that the user is only performing an action on its own data, but in a big application with 200+ servlets and 50-100 tables this could be a very cumbersome task where mistakes could easily happen. In my mind this weakens the security far more, but I'm not sure if that is true.
I'm leaning towards the UUID solution, but I'm also curious if there are other obvious approaches to this problem that I ought to consider.
Update:
I should probably have clarified that my plan would be to use UUIDv4 which is supposed to be random. I know that entropy comes in to play here in regards to how random the UUID's actually are, but as far as I have read then Java (which is the selected platform/language) uses SecureRandom which is supposed to be "cryptographically strong" (link).
And in that case wiki states (link):
In other words, only after generating 1 billion UUIDs every second for the next 100 years, the probability of creating just one duplicate would be about 50%.
Using UUIDs in this manner has two major issues:
If there are no additional authentication methods, any attacker could simply guess UUIDs until they find one belonging to someone else. Google Photos doesn't need to worry about this as much, because they only use UUIDs to obfuscate publicly-shared photo views; you still need to authenticate to modify the photos. This is especially dangerous because:
UUIDs are intended to be unique, not random. There are likely to be predictable patterns in your UUIDs that an attacker would be able to observe and take advantage of. In addition, even without a clear pattern, the number of UUIDs an attacker needs to test to find a valid one swiftly decreases as your userbase grows.
I will always recommend using secure, continuously-checked authentication. However, if you have a fairly small userbase, and you are only using this to obfuscate public data access, then using UUIDs in this manner might be alright. Even then, you should be using actual random strings, and not UUIDs.
Another option is off cause to have every servlet verify that the user
is only performing an action on its own data, but in a big application
with 200+ servlets and 50-100 tables this could be a very cumbersome
task where mistakes could easily happen. In my mind this weakens the
security far more, but I'm not sure if that is true.
With a large legacy application adding in security later is always a complex task. And you're right - the more complicated an application, the harder it is to verify security. Complexity is the main enemy of security.
However, this is the best way to go rather than by trying to obscure insecure direct object reference problems.
If you are using these UUIDs in the query string then this information within URLs may be logged in various locations, including the user's browser, the web server, and any forward or reverse proxy servers between the two endpoints. URLs may also be displayed on-screen, bookmarked or emailed around by users. They may be disclosed to third parties via the Referer header when any off-site links are followed. Placing direct object references into the URL increases the risk that they will be captured by an attacker. An existing user of the application that then has their access revoked to certain bits of data - they will still be able to access this data by using a previously bookmarked URL (or by using their browser history). Even where the ID is passed outside of the URL mechanism, a local attacker that knows (or has figured out) how your system works could have purposely saved IDs just for the occasion.
As said by other answers, GUIDs/UUIDs are not meant to be unguessable, they are just meant to be unique. Granted, the Java implementation does actually generate cryptographically secure random numbers. However, what if this implementation changes in future releases, or what if your system is ported elsewhere where this functionality is different? If you're going to do this, you might as well generate your own cryptographically secure random numbers using your own implementation to use as identifiers. If you have 128bits of entropy in your identifiers, it is completely infeasible for anyone ever to guess them (even if they had all of the world's computing power).
However, for the above reasons I recommend you implement access checks instead.
You are trying to bypass authorisation controls by hoping that the key is unguessable. This is a security no-no. Depending on whom you ask, they may refer to it as an insecure direct object reference or a violation of the complete mediation principle.
As noted by F. Stephen Q, your assumption that UUIDs are unique does not imply that they are not predictable. The threat here is that if a user knows a few UUIDs, say his own, does that allow him to predict other peoples' UUIDs? This is a very real threat, see: Cautionary note: UUIDs generally do not meet security requirements. Especially note what the UUID RFC says:
Do not assume that UUIDs are hard to guess; they should not be used as
security capabilities (identifiers whose mere possession grants
access), for example.
You can use UUIDs for keys, but you still need to do authorisation checks. When a user wants to access his data, the database should identify the owner of the data, and the server logic needs to enforce that the current user is the same as the database claims the owner is.

Two OwnerPIN object in Java Card

I am working on a Java Card application where our requirement is to keep some static data and balance in the card.
For security I was thinking to make 2 object of OwnerPIN. One object is for terminal authentication (i.e. the terminal needs to send 8 bytes of data to authenticate itself) and the other object is for user authentication (i.e. the user needs to enter a 4 digit PIN to authenticate theirself)
Only if both authentications are successful, we can read the data or update the balance.
Or is there any other advice on how to implement security on card to avoid theft?
Also is there any guideline for choosing proprietary class and instruction bytes during applet development?
For user authentication, the OwnerPIN is certainly one good way to go (there are alternatives ofcourse, but OwnerPIN provides security features (e.g. tearing protection) that you would otherwise have to implement manually).
For terminal authentication, nothing should prevent you from using an approach based on an instance of the OwnerPIN. However, depending on your security requirements, you might want to choose some form of mutual authentication instead of a simple PIN code. If the terminal simply sends a PIN code (especially if it does that in plain text), an attacker could simply intercept that PIN code (while sent to a card) and then use that discovered PIN code to create their own (malicious) terminal.
With regard to class and instruction byte (and especially with regard to standard operations like PIN code verification) I would suggest that you stick to standards. ISO/IEC 7816-4 defines many instructions for such standard operations.

what is the state of the art algorithm to encrypt credit card data

We have a business requirement to keep credit card data. What is today's (Nov 2013) state of the art algorithm to encrypt credit card data that will be saved on disk?
Additionally, I'd appreciate pointers to Java libraries that implement these algorithms
Note that we are PCI compliant and we already store credit card data. I am doing a review to make sure that our encryption method remains state-of-the-art
I recently just left the credit card industry as a developer to work in security in non PCI compliant field. BCrypt is a great choice. It allows a one way hash as well as a work parameter that forces time per attempt. This allows you to stop brut force attacks.
I would use one of the block ciphers approved by ISO/IEC 18033: AES, Camellia, and SEED.
It's hard to go wrong with AES256.
Just go ahead with AES 256 but make sure you choose right mode. I don't agree with comment "It's hard to go wrong with AES256." Check out - https://pthree.org/2012/02/17/ecb-vs-cbc-encryption/
Needless to say, you need to take care of key management and avoid any issues with IV- a message "hello world" encrypted with a key1+IV1 combination will look exactly the same in ciphertext every time you run your encryption. So make sure you are choosing your IVs randomly from a large entropy pool
From Java implementation perspective, Java has native support for AES encryption. Just make sure if you are using 256 bit encryption, you have the right unlimited strength JCE files - without these JCE files which provide crypto methods, you will be limited to 128 bit encryption.
Checkout this if you don't want to reply upon these JCE files available on server running your application.
As #gauravphoenix points out, it is actually quite easy to go wrong with AES. The AES algorithm itself can only securely encrypt exactly 16 bytes of data if you give it a totally random key. If your problem is anything other than that (and almost everyone's problem is something different than that), you need to add more pieces to it. Specifically you need to choose an appropriate mode, configure that mode correctly, properly generate a key, and protect against modification. AES does none of this for you automatically, and unfortunately, most example code on the internet does it incorrectly.
There are a few libraries that attempt to bundle all of these details for you so that you can just make the silly "please encrypt this data" call that most people would like to make. I maintain one for iOS called RNCryptor. There are a bunch of ports of the format to other languages, including a Java implementation called JNCryptor.
Another good "whole solution" AES implementation is aescrypt, which includes a Java implementation.
Note that the most important technical(*) step of securing the data is not your selection of algorithm or format. It's how you manage the keys. If you store the key on the same disk as the credit card numbers, or hard-code it into your software, then it doesn't really matter how strong your encryption is. The state of the art in key management is called an HSM (Hardware Security Module). Companies like SafeNet make them. They can be rack-mounted, plug-in cards, or even USB dongles. I've worked with the Luna, and was generally pleased with it, but there are several options on the market.
(*) While key management is IMO the most important technical step, it is by far not the most important step in securing credit cards (or anything else). The most important step is having procedures in place that encourage secure design, pre- and post-release security review, and a commitment to remediation of security findings.

Collecting Credit Card Information - not to collect payment

I am working in PHP on a Linux server with MySQL.
I have a requirement (that I have attempted to talk them out of) to collect credit card information from users so that our company can use the card numbers to hold hotel rooms for a conference. We will not be charging the cards ourselves at all, but instead just sending them to the hotel. I then need to be able to download a CSV file and each time someone signs up an email to go to the admin with all the information.
I tried to explain that this wasn't secure, but several other developers have done this for them in the past before I was working here.
My question is; is there anyway to make this secure? If not are there any third party options to make this happen?
EDIT:
I appreciate everyone who has posted so far, it has simply made me want to attempt to do this less and less. If you could add to your answers simple explanations, oriented at non-tech people, it would be greatly appreciated, in fact site source and links would help me a great deal. I haven't found any sites that would explain this in a non-tech way.
First of, I am not a lawyer. I have implemented CC-handling code several times previously, but I am only familiar with Danish laws and regulations, so your mileage may vary.
As far as I know, there are restrictions in place (law and regulations from the CC providers) that you need to be aware of. I don't know where you are in the world, but in many countries you need to be PCI certified to handle credit card data and that is an extremely onerous, expensive and on-going process.
Other countries, or states, may have notification rules in play that requires you to pay the cost of notifying the card holder if security is broken - and unless you are very careful, it is not unlikely.
In general, I would recommend against that procedure. You may risk being liable for any costs if it goes wrong.
It's really a bad idea to be storing card details. You're opening yourself up for a world of pain in the form of PCI-DSS audits. It is not as simple as 'use encryption', you need to have processes in place to securely manage the encryption keys, schedule key rotation, securely log access and so on and on... Storing card details is absolutely something you want to avoid.
If you have to have something in place, then the best option may be for you (as a company) to take payments from the credit cards to your own merchant account, then pay the hotels separately (from your bank account/whatever). You act as a proxy for the client making the payment to the hotel.
Most payment gateways allow you to store the card details securely, and charge at a later date (using a token id returned by the gateway), which will likely be useful here. But you wont be able to retrieve the card details to pass them through to the hotel in any way, which is why you would need to take payment, then organise a separate payment to the hotel.
Its still quite an undertaking though because a lot of areas of PCI-DSS will come into play even with this simplified solution.
You asked, so here is more information:
PCI-DSS is the Payment Card Industry Data Security Standard. It's a set of guidelines which basically apply to any company that 'touches' cardholder data, in particular the card number. Touching it literally means any handling of the data, even just having it pass through your network without it ever being persisted to disk is enough to mandate that you must comply, (though it is significantly easier if you don't persist the details to disk)
You didn't yet state which part of the world you're in, or how these card details are captured (internet/telephone/in person). These details are significant to how you can achieve compliance.
Start by taking a look at the PCI-DSS SAQ (Self Assessment Questionnaires). These SAQ's are the minimum requirements for companies that do not store cardholder details to disk, and should give a good impression of the security that needs to be in place across the network and policies that should be applied across the company.
As I said, if you're thinking of storing card details then things get more complicated, because as a general rule the SAQ is no longer good enough. You need to enrol the assistance of a QSA (Qualified Security Assessor) who will visit and advise on best practice for data storage and the various other points that come into play. For this level of compliance you're looking at yearly audits (carried out by the QSA), and quarterly network scans. Take a look at the audit procedures to get a detailed look at what is involved. In particular take a look at section 3 and do not underestimate the difficulty of implementing proper key management.
In summary, full PCI compliance will be very costly. Even for a company which already has pretty strong security policies the cost of bringing in a QSA and running quarterly scans and yearly audits alone will likely cost $thousands.
This is very insecure and I think you're correct for opposing it. That said...
Some ideas:
Can the hotel give you a rate/group code that you can disseminate to your users directly? Perhaps you could even give them a link that goes right to the hotel's reservation page, with the code already filled in.
Don't even think about implementing this unless you can do it on an SSL-enabled site.
Don't save the CC number anywhere,
just generate the email and toss the
number out. This alleviates you from having to worry about a ton of very difficult application / server security issues.
Encrypt the email with GPG or
equivalent so that it's protected in
transit and can only be read by the intended recipient.
I suggest you follow the Card Industry PCI compliance closely at least. Here is a PDF document.
As someone who has worked on a system like this, it is 100% illegal to store any credit card information in plain text. You must encrypt all of the data and you are not allowed to know any piece of the keys. It is quite the catch 22, the only way to validate data is to guess as sad as that sounds. This is the exact reason why accidental charges occur.
As others have said here, it's a fact that storing credit card information requires you to be certified. You can ask for information to process the transaction but keeping it on storage of any kind is a big no-no.
Fortunately sites like authorize.net, braintree.com, paypal.com, etc will let you interact with their APIs in such a way that you get a "Customer Vault ID" for each entity you'd like to make transactions for.
These 3rd parties store all the sensitive information in a 100% legit way. And whenever you would like to make a transaction using their saved information, you interact with the service using their "Vault ID".
I've used authorize.net, BrainTree and PayPal. Most recently it was BrainTree and had some good success with them. I would not recommend PayPal unless you need the brand recognition or you just want to do a direct transfer whereby you bypass asking them for account information of any kind (because they already entered it in PayPal).
Make sure your server is as secure as possible and prove that it isn't already compromised. None of this will really work well if you have a compromised server.
Use SSL to protect this information during transit.
Encrypt these details immediately upon receipt. This will help protect it at rest. If possible, encrypt it with a public key for a key pair where the private key (used for decryption) is not on your server. This could easily be that you place this information into the body of the email that you're required to send, then encrypt the body with public-key encryption where your client has the private key. (You could use PGP here). In this way, the data is help on your server as briefly as possible, then once off your server, is accessible only by your client. If you use a symmetric encryption algorithm, then your key will necessarily also be on your server somewhere (on disk, in memory, etc.), which could be obtained and used by an attacker to regain access to the details.
This isn't an endorsement, per se, but I have used this before in similar situations with good results: http://www.pgp.com/products/commandline/
Remember that there are always security holes, but you'll be raising a large barrier against attacks with these steps. I might also add that you look into a system integrity solution like Trip Wire from the immediate build of your server. And of course, ensure that all of your passwords are strong.
If you send the file via email, be sure to use secured connexions (HTTPS / IMAP or POP3 over SSL, SMTP over SSL) on both sending and receiving computers and have the file encrypted prior sending. You can encrypt your mail and attachment via OpenPGP, too. Also, ensure the security between the two mail servers (sending and receiving), or simply use the same domain for sending and receiving email addresses. Do not use the password-feature of a ZIP file or related comrpessing container, since they are usually cryptographically weak.
If you send it on a filesystem (ie. USB pendrive), be sure to use a crypted one (ie. TrueCrypt).
Be sure to have a secured computer where the download and upload takes part (encrypted partition where the download/upload takes place, no spywares on the system, passworded system, firewalled).

Security risk when store private data

I have to handle some sensitive data in my application, such as passwords, credit card information, etc.
What are possible security risks I could have and how can I avoid them?
Don't store Credit Card Information (in some jurisdictions, you might be breaking the law by doing so, or at least falling foul of a commercial agreement)
You don't say where your sensitive data is stored, but encypting it is the usual approach. There are two forms symmetric and asymmetric. Symmetric means you use the same key for encrypting and decrypting. Asymmetric consists of a public/private key pair.
Passwords: store only a salted hash (i.e. un-reversible) of your passwords, and compare with a similarly salted hash of an entered password.
Be aware that you really shouldn't store credit card info in any shape or form on a web server.
Bit of info on doing this in a web environment, which is my background:
If a website (or any application) needs to store card info, it should comply with the PCI DSS (Payment Cards Industry Data Security Standard). Amongst other things, it requires that the data be held encrypted on a separate server that isn't publicly accessible (IE: isn't hosting the site) and has a separate firewall between it and the webserver. Penalties for not complying are potentially very large in the event of any fraudulent activity following a security breach, and can include them ceasing working with you - it pretty much reserves the right for the them to chargeback any losses from the fraud to you (from my interpretation as a non legal person)
More on it here: https://www.pcisecuritystandards.org/security_standards/pci_dss.shtml
Obviously, this may be expensive compared to shared hosting, as you immediately need two servers and a load of networking gear. Which is why people don't often do this.
I would be inclined to perform some form of reversible encryption on the information as it's being stored, something like:
$card = myEncryptionFunction($input);
A little more information on the nature of your application wouldn't hurt though.
I'd be using reversible encryption on the database data. Make sure this data doesn't seep into log-files too, log derived information instead. Consider how yoǘ'll handle different environments - normally you want to not use production data in your test environments. So even though you may consider copying production data back to test systems, you should probably generate fake data for the sensitive parts.
It's been already said that you shouldn't store CC especially CVV2 information in your database, avoid where possible.
If you store CC + CVV2 then consider using asymmetric encryption and store your private key in another server. Otherwise an attacker who can access the data 99% can access the key and the whole encryption would be pointless.
Passwords should be stored as one way hashed.
After all these you need to ensure that your application is secure against vulnerabilities such as SQL Injeciton, remote code execution etc.
Don't forget Even when an attacker can't read previous data they can plant a backdoor for the next data.

Resources