This page is about accepting, storing and processing credit cards. -------------------- A brief, high level overview of accepting payments on-line, with a focus on credit cards is at http://selfpromotion.com/credit.t -- ChuckEsterbrook_ - 18 Mar 2002 -------------------- This information comes courtesy of Jeff Johnson: How to Store Credit Card Numbers -------------------------------- For starters, you'll likely store them in a SQL database. You'll want to encrypt them for safekeeping, but might also choose to store the last 4 digits as plain text so that customer service reps can tell a customer which card they used (without seeing the whole number). You can encrypt them using either M2Crypto_ or the Python rotor_ library. .. _M2Crypto: http://www.post1.com/home/ngps/m2/ .. _rotor: http://python.org/doc/current/lib/module-rotor.html -------------------- The rotor module implements an encryption algorithm used in the second world war. Beware that data encrypted with this algorithm are easily cracked! --AlbertBrandl_ Here's an interesting link about credit card handling, including the pitfalls of not retaining card information: http://www.arsdigita.com/books/panda/ecommerce#credit_cards -- PaulBoddie_ - 06 Mar 2002 -------------------- Here's what Jeff Johnson said: I store them encrypted using the rotor library, I might use M2Crypto if I were to do it again but so far rotor is fine. I also store the last 4 digits as plain text so CSRs can tell the customer which card they used without seeing the whole number. Then, I store the hash so we can search the database and compare numbers without passing the actual number. Here's my code, altered a little for security reasons:: def decryptCreditCard(self,number): r = rotor.newrotor(???,???) number = binascii.a2b_hex(number) number = r.decrypt(number) number = re.sub(r"\D","",number) return number def encryptCreditCard(self,number): number = re.sub(r"\D","",number) r = rotor.newrotor(???,???) number = r.encrypt(number) number = binascii.b2a_hex(number) return number def creditCardShaHex(self,number): number = re.sub(r"\D","",number) return binascii.b2a_hex(sha.new(number).digest()) def creditCardFromNumber(self,number): number = re.sub(r"\D","",number) numberShaHex = self.creditCardShaHex(number) sql = " select creditCardID,number,expiration,numberShaHex,numberPart from CreditCard where numberShaHex = '%s' " % numberShaHex rs = self.recordset("DEG",sql) if rs: return rs[0] else: return None def creditCardFromID(self,creditCardID): sql = " select creditCardID,number,expiration,numberShaHex,numberPart from CreditCard where creditCardID = %s " % creditCardID rs = self.recordset("DEG",sql) if rs: return rs[0] else: return None def insertCreditCard(self,number,expiration): # Get rid of non-digits (\D). number = re.sub(r"\D","",number) expiration = re.sub(r"\D","",expiration) # Encrypt the number before storing it. numberRotor = self.encryptCreditCard(number,expiration) # To find a credit card in the database, get the sha hex value, then query the database. numberShaHex = self.creditCardShaHex(number) # If a customer wants to know which card they used, read the last 4 digits back to them. numberPart = number[-4:] sql = """ select nextval('CreditCardSeq') as creditCardID """ rs = self.recordset("DEG",sql) creditCardID = rs[0].creditCardID sql = """ insert into CreditCard (creditCardID,number,expiration,numberShaHex,numberPart) values (%(creditCardID)d,'%(numberRotor)s','%(expiration)s','%(numberShaHex)s','%(numberPart)s') """ % locals() rs = self.recordset("DEG",sql) return creditCardID SSL --- You'll need SSL for encryption. You can run Apache 1.3.x + mod_ssl and get SSL certs from a variety of companies. http://google.com/search?q=buy+ssl+certificates You can use stunnel to talk SSL to the credit card company. .. _stunnel: http://www.stunnel.org/ -- ChuckEsterbrook_ - 04 Mar 2002