pci-compliance
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePCI Compliance
PCI合规
Master PCI DSS (Payment Card Industry Data Security Standard) compliance for secure payment processing and handling of cardholder data.
掌握PCI DSS(支付卡行业数据安全标准)合规要求,实现安全的支付处理和持卡人数据管理。
When to Use This Skill
何时使用此技能
- Building payment processing systems
- Handling credit card information
- Implementing secure payment flows
- Conducting PCI compliance audits
- Reducing PCI compliance scope
- Implementing tokenization and encryption
- Preparing for PCI DSS assessments
- 构建支付处理系统
- 处理信用卡信息
- 实施安全支付流程
- 开展PCI合规审计
- 缩小PCI合规范围
- 实施令牌化和加密
- 为PCI DSS评估做准备
PCI DSS Requirements (12 Core Requirements)
PCI DSS核心要求(12项)
Build and Maintain Secure Network
构建并维护安全网络
- Install and maintain firewall configuration
- Don't use vendor-supplied defaults for passwords
- 安装并维护防火墙配置
- 不要使用供应商提供的默认密码
Protect Cardholder Data
保护持卡人数据
- Protect stored cardholder data
- Encrypt transmission of cardholder data across public networks
- 保护存储的持卡人数据
- 在公共网络上加密传输持卡人数据
Maintain Vulnerability Management
维护漏洞管理计划
- Protect systems against malware
- Develop and maintain secure systems and applications
- 保护系统免受恶意软件侵害
- 开发并维护安全的系统和应用程序
Implement Strong Access Control
实施严格的访问控制措施
- Restrict access to cardholder data by business need-to-know
- Identify and authenticate access to system components
- Restrict physical access to cardholder data
- 根据业务需求限制对持卡人数据的访问
- 识别并验证对系统组件的访问权限
- 限制对持卡人数据的物理访问
Monitor and Test Networks
监控和测试网络
- Track and monitor all access to network resources and cardholder data
- Regularly test security systems and processes
- 跟踪并监控对网络资源和持卡人数据的所有访问
- 定期测试安全系统和流程
Maintain Information Security Policy
维护信息安全政策
- Maintain a policy that addresses information security
- 制定并维护信息安全政策
Compliance Levels
合规等级
Level 1: > 6 million transactions/year (annual ROC required)
Level 2: 1-6 million transactions/year (annual SAQ)
Level 3: 20,000-1 million e-commerce transactions/year
Level 4: < 20,000 e-commerce or < 1 million total transactions
等级1:年交易量>600万笔(需年度合规报告ROC)
等级2:年交易量100万-600万笔(需年度自我评估问卷SAQ)
等级3:年电商交易量2万-100万笔
等级4:年电商交易量<2万笔或总交易量<100万笔
Data Minimization (Never Store)
数据最小化(禁止存储)
python
undefinedpython
undefinedNEVER STORE THESE
NEVER STORE THESE
PROHIBITED_DATA = {
'full_track_data': 'Magnetic stripe data',
'cvv': 'Card verification code/value',
'pin': 'PIN or PIN block'
}
PROHIBITED_DATA = {
'full_track_data': 'Magnetic stripe data',
'cvv': 'Card verification code/value',
'pin': 'PIN or PIN block'
}
CAN STORE (if encrypted)
CAN STORE (if encrypted)
ALLOWED_DATA = {
'pan': 'Primary Account Number (card number)',
'cardholder_name': 'Name on card',
'expiration_date': 'Card expiration',
'service_code': 'Service code'
}
class PaymentData:
"""Safe payment data handling."""
def __init__(self):
self.prohibited_fields = ['cvv', 'cvv2', 'cvc', 'pin']
def sanitize_log(self, data):
"""Remove sensitive data from logs."""
sanitized = data.copy()
# Mask PAN
if 'card_number' in sanitized:
card = sanitized['card_number']
sanitized['card_number'] = f"{card[:6]}{'*' * (len(card) - 10)}{card[-4:]}"
# Remove prohibited data
for field in self.prohibited_fields:
sanitized.pop(field, None)
return sanitized
def validate_no_prohibited_storage(self, data):
"""Ensure no prohibited data is being stored."""
for field in self.prohibited_fields:
if field in data:
raise SecurityError(f"Attempting to store prohibited field: {field}")undefinedALLOWED_DATA = {
'pan': 'Primary Account Number (card number)',
'cardholder_name': 'Name on card',
'expiration_date': 'Card expiration',
'service_code': 'Service code'
}
class PaymentData:
"""Safe payment data handling."""
def __init__(self):
self.prohibited_fields = ['cvv', 'cvv2', 'cvc', 'pin']
def sanitize_log(self, data):
"""Remove sensitive data from logs."""
sanitized = data.copy()
# Mask PAN
if 'card_number' in sanitized:
card = sanitized['card_number']
sanitized['card_number'] = f"{card[:6]}{'*' * (len(card) - 10)}{card[-4:]}"
# Remove prohibited data
for field in self.prohibited_fields:
sanitized.pop(field, None)
return sanitized
def validate_no_prohibited_storage(self, data):
"""Ensure no prohibited data is being stored."""
for field in self.prohibited_fields:
if field in data:
raise SecurityError(f"Attempting to store prohibited field: {field}")undefinedTokenization
令牌化
Using Payment Processor Tokens
使用支付处理器令牌
python
import stripe
class TokenizedPayment:
"""Handle payments using tokens (no card data on server)."""
@staticmethod
def create_payment_method_token(card_details):
"""Create token from card details (client-side only)."""
# THIS SHOULD ONLY BE DONE CLIENT-SIDE WITH STRIPE.JS
# NEVER send card details to your server
"""
// Frontend JavaScript
const stripe = Stripe('pk_...');
const {token, error} = await stripe.createToken({
card: {
number: '4242424242424242',
exp_month: 12,
exp_year: 2024,
cvc: '123'
}
});
// Send token.id to server (NOT card details)
"""
pass
@staticmethod
def charge_with_token(token_id, amount):
"""Charge using token (server-side)."""
# Your server only sees the token, never the card number
stripe.api_key = "sk_..."
charge = stripe.Charge.create(
amount=amount,
currency="usd",
source=token_id, # Token instead of card details
description="Payment"
)
return charge
@staticmethod
def store_payment_method(customer_id, payment_method_token):
"""Store payment method as token for future use."""
stripe.Customer.modify(
customer_id,
source=payment_method_token
)
# Store only customer_id and payment_method_id in your database
# NEVER store actual card details
return {
'customer_id': customer_id,
'has_payment_method': True
# DO NOT store: card number, CVV, etc.
}python
import stripe
class TokenizedPayment:
"""Handle payments using tokens (no card data on server)."""
@staticmethod
def create_payment_method_token(card_details):
"""Create token from card details (client-side only)."""
# THIS SHOULD ONLY BE DONE CLIENT-SIDE WITH STRIPE.JS
# NEVER send card details to your server
"""
// Frontend JavaScript
const stripe = Stripe('pk_...');
const {token, error} = await stripe.createToken({
card: {
number: '4242424242424242',
exp_month: 12,
exp_year: 2024,
cvc: '123'
}
});
// Send token.id to server (NOT card details)
"""
pass
@staticmethod
def charge_with_token(token_id, amount):
"""Charge using token (server-side)."""
# Your server only sees the token, never the card number
stripe.api_key = "sk_..."
charge = stripe.Charge.create(
amount=amount,
currency="usd",
source=token_id, # Token instead of card details
description="Payment"
)
return charge
@staticmethod
def store_payment_method(customer_id, payment_method_token):
"""Store payment method as token for future use."""
stripe.Customer.modify(
customer_id,
source=payment_method_token
)
# Store only customer_id and payment_method_id in your database
# NEVER store actual card details
return {
'customer_id': customer_id,
'has_payment_method': True
# DO NOT store: card number, CVV, etc.
}Custom Tokenization (Advanced)
自定义令牌化(高级)
python
import secrets
from cryptography.fernet import Fernet
class TokenVault:
"""Secure token vault for card data (if you must store it)."""
def __init__(self, encryption_key):
self.cipher = Fernet(encryption_key)
self.vault = {} # In production: use encrypted database
def tokenize(self, card_data):
"""Convert card data to token."""
# Generate secure random token
token = secrets.token_urlsafe(32)
# Encrypt card data
encrypted = self.cipher.encrypt(json.dumps(card_data).encode())
# Store token -> encrypted data mapping
self.vault[token] = encrypted
return token
def detokenize(self, token):
"""Retrieve card data from token."""
encrypted = self.vault.get(token)
if not encrypted:
raise ValueError("Token not found")
# Decrypt
decrypted = self.cipher.decrypt(encrypted)
return json.loads(decrypted.decode())
def delete_token(self, token):
"""Remove token from vault."""
self.vault.pop(token, None)python
import secrets
from cryptography.fernet import Fernet
class TokenVault:
"""Secure token vault for card data (if you must store it)."""
def __init__(self, encryption_key):
self.cipher = Fernet(encryption_key)
self.vault = {} # In production: use encrypted database
def tokenize(self, card_data):
"""Convert card data to token."""
# Generate secure random token
token = secrets.token_urlsafe(32)
# Encrypt card data
encrypted = self.cipher.encrypt(json.dumps(card_data).encode())
# Store token -> encrypted data mapping
self.vault[token] = encrypted
return token
def detokenize(self, token):
"""Retrieve card data from token."""
encrypted = self.vault.get(token)
if not encrypted:
raise ValueError("Token not found")
# Decrypt
decrypted = self.cipher.decrypt(encrypted)
return json.loads(decrypted.decode())
def delete_token(self, token):
"""Remove token from vault."""
self.vault.pop(token, None)Encryption
加密
Data at Rest
静态数据加密
python
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
class EncryptedStorage:
"""Encrypt data at rest using AES-256-GCM."""
def __init__(self, encryption_key):
"""Initialize with 256-bit key."""
self.key = encryption_key # Must be 32 bytes
def encrypt(self, plaintext):
"""Encrypt data."""
# Generate random nonce
nonce = os.urandom(12)
# Encrypt
aesgcm = AESGCM(self.key)
ciphertext = aesgcm.encrypt(nonce, plaintext.encode(), None)
# Return nonce + ciphertext
return nonce + ciphertext
def decrypt(self, encrypted_data):
"""Decrypt data."""
# Extract nonce and ciphertext
nonce = encrypted_data[:12]
ciphertext = encrypted_data[12:]
# Decrypt
aesgcm = AESGCM(self.key)
plaintext = aesgcm.decrypt(nonce, ciphertext, None)
return plaintext.decode()python
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
class EncryptedStorage:
"""Encrypt data at rest using AES-256-GCM."""
def __init__(self, encryption_key):
"""Initialize with 256-bit key."""
self.key = encryption_key # Must be 32 bytes
def encrypt(self, plaintext):
"""Encrypt data."""
# Generate random nonce
nonce = os.urandom(12)
# Encrypt
aesgcm = AESGCM(self.key)
ciphertext = aesgcm.encrypt(nonce, plaintext.encode(), None)
# Return nonce + ciphertext
return nonce + ciphertext
def decrypt(self, encrypted_data):
"""Decrypt data."""
# Extract nonce and ciphertext
nonce = encrypted_data[:12]
ciphertext = encrypted_data[12:]
# Decrypt
aesgcm = AESGCM(self.key)
plaintext = aesgcm.decrypt(nonce, ciphertext, None)
return plaintext.decode()Usage
Usage
storage = EncryptedStorage(os.urandom(32))
encrypted_pan = storage.encrypt("4242424242424242")
storage = EncryptedStorage(os.urandom(32))
encrypted_pan = storage.encrypt("4242424242424242")
Store encrypted_pan in database
Store encrypted_pan in database
undefinedundefinedData in Transit
传输数据加密
python
undefinedpython
undefinedAlways use TLS 1.2 or higher
Always use TLS 1.2 or higher
Flask/Django example
Flask/Django example
app.config['SESSION_COOKIE_SECURE'] = True # HTTPS only
app.config['SESSION_COOKIE_HTTPONLY'] = True
app.config['SESSION_COOKIE_SAMESITE'] = 'Strict'
app.config['SESSION_COOKIE_SECURE'] = True # HTTPS only
app.config['SESSION_COOKIE_HTTPONLY'] = True
app.config['SESSION_COOKIE_SAMESITE'] = 'Strict'
Enforce HTTPS
Enforce HTTPS
from flask_talisman import Talisman
Talisman(app, force_https=True)
undefinedfrom flask_talisman import Talisman
Talisman(app, force_https=True)
undefinedAccess Control
访问控制
python
from functools import wraps
from flask import session
def require_pci_access(f):
"""Decorator to restrict access to cardholder data."""
@wraps(f)
def decorated_function(*args, **kwargs):
user = session.get('user')
# Check if user has PCI access role
if not user or 'pci_access' not in user.get('roles', []):
return {'error': 'Unauthorized access to cardholder data'}, 403
# Log access attempt
audit_log(
user=user['id'],
action='access_cardholder_data',
resource=f.__name__
)
return f(*args, **kwargs)
return decorated_function
@app.route('/api/payment-methods')
@require_pci_access
def get_payment_methods():
"""Retrieve payment methods (restricted access)."""
# Only accessible to users with pci_access role
passpython
from functools import wraps
from flask import session
def require_pci_access(f):
"""Decorator to restrict access to cardholder data."""
@wraps(f)
def decorated_function(*args, **kwargs):
user = session.get('user')
# Check if user has PCI access role
if not user or 'pci_access' not in user.get('roles', []):
return {'error': 'Unauthorized access to cardholder data'}, 403
# Log access attempt
audit_log(
user=user['id'],
action='access_cardholder_data',
resource=f.__name__
)
return f(*args, **kwargs)
return decorated_function
@app.route('/api/payment-methods')
@require_pci_access
def get_payment_methods():
"""Retrieve payment methods (restricted access)."""
# Only accessible to users with pci_access role
passAudit Logging
审计日志
python
import logging
from datetime import datetime
class PCIAuditLogger:
"""PCI-compliant audit logging."""
def __init__(self):
self.logger = logging.getLogger('pci_audit')
# Configure to write to secure, append-only log
def log_access(self, user_id, resource, action, result):
"""Log access to cardholder data."""
entry = {
'timestamp': datetime.utcnow().isoformat(),
'user_id': user_id,
'resource': resource,
'action': action,
'result': result,
'ip_address': request.remote_addr
}
self.logger.info(json.dumps(entry))
def log_authentication(self, user_id, success, method):
"""Log authentication attempt."""
entry = {
'timestamp': datetime.utcnow().isoformat(),
'user_id': user_id,
'event': 'authentication',
'success': success,
'method': method,
'ip_address': request.remote_addr
}
self.logger.info(json.dumps(entry))python
import logging
from datetime import datetime
class PCIAuditLogger:
"""PCI-compliant audit logging."""
def __init__(self):
self.logger = logging.getLogger('pci_audit')
# Configure to write to secure, append-only log
def log_access(self, user_id, resource, action, result):
"""Log access to cardholder data."""
entry = {
'timestamp': datetime.utcnow().isoformat(),
'user_id': user_id,
'resource': resource,
'action': action,
'result': result,
'ip_address': request.remote_addr
}
self.logger.info(json.dumps(entry))
def log_authentication(self, user_id, success, method):
"""Log authentication attempt."""
entry = {
'timestamp': datetime.utcnow().isoformat(),
'user_id': user_id,
'event': 'authentication',
'success': success,
'method': method,
'ip_address': request.remote_addr
}
self.logger.info(json.dumps(entry))Usage
Usage
audit = PCIAuditLogger()
audit.log_access(user_id=123, resource='payment_methods', action='read', result='success')
undefinedaudit = PCIAuditLogger()
audit.log_access(user_id=123, resource='payment_methods', action='read', result='success')
undefinedSecurity Best Practices
安全最佳实践
Input Validation
输入验证
python
import re
def validate_card_number(card_number):
"""Validate card number format (Luhn algorithm)."""
# Remove spaces and dashes
card_number = re.sub(r'[\s-]', '', card_number)
# Check if all digits
if not card_number.isdigit():
return False
# Luhn algorithm
def luhn_checksum(card_num):
def digits_of(n):
return [int(d) for d in str(n)]
digits = digits_of(card_num)
odd_digits = digits[-1::-2]
even_digits = digits[-2::-2]
checksum = sum(odd_digits)
for d in even_digits:
checksum += sum(digits_of(d * 2))
return checksum % 10
return luhn_checksum(card_number) == 0
def sanitize_input(user_input):
"""Sanitize user input to prevent injection."""
# Remove special characters
# Validate against expected format
# Escape for database queries
passpython
import re
def validate_card_number(card_number):
"""Validate card number format (Luhn algorithm)."""
# Remove spaces and dashes
card_number = re.sub(r'[\s-]', '', card_number)
# Check if all digits
if not card_number.isdigit():
return False
# Luhn algorithm
def luhn_checksum(card_num):
def digits_of(n):
return [int(d) for d in str(n)]
digits = digits_of(card_num)
odd_digits = digits[-1::-2]
even_digits = digits[-2::-2]
checksum = sum(odd_digits)
for d in even_digits:
checksum += sum(digits_of(d * 2))
return checksum % 10
return luhn_checksum(card_number) == 0
def sanitize_input(user_input):
"""Sanitize user input to prevent injection."""
# Remove special characters
# Validate against expected format
# Escape for database queries
passPCI DSS SAQ (Self-Assessment Questionnaire)
PCI DSS SAQ(自我评估问卷)
SAQ A (Least Requirements)
SAQ A(要求最少)
- E-commerce using hosted payment page
- No card data on your systems
- ~20 questions
- 使用托管支付页面的电商场景
- 系统中不存储卡数据
- 约20个问题
SAQ A-EP
SAQ A-EP
- E-commerce with embedded payment form
- Uses JavaScript to handle card data
- ~180 questions
- 使用嵌入式支付表单的电商场景
- 通过JavaScript处理卡数据
- 约180个问题
SAQ D (Most Requirements)
SAQ D(要求最多)
- Store, process, or transmit card data
- Full PCI DSS requirements
- ~300 questions
- 存储、处理或传输卡数据
- 需满足完整的PCI DSS要求
- 约300个问题
Compliance Checklist
合规检查清单
python
PCI_COMPLIANCE_CHECKLIST = {
'network_security': [
'Firewall configured and maintained',
'No vendor default passwords',
'Network segmentation implemented'
],
'data_protection': [
'No storage of CVV, track data, or PIN',
'PAN encrypted when stored',
'PAN masked when displayed',
'Encryption keys properly managed'
],
'vulnerability_management': [
'Anti-virus installed and updated',
'Secure development practices',
'Regular security patches',
'Vulnerability scanning performed'
],
'access_control': [
'Access restricted by role',
'Unique IDs for all users',
'Multi-factor authentication',
'Physical security measures'
],
'monitoring': [
'Audit logs enabled',
'Log review process',
'File integrity monitoring',
'Regular security testing'
],
'policy': [
'Security policy documented',
'Risk assessment performed',
'Security awareness training',
'Incident response plan'
]
}python
PCI_COMPLIANCE_CHECKLIST = {
'network_security': [
'Firewall configured and maintained',
'No vendor default passwords',
'Network segmentation implemented'
],
'data_protection': [
'No storage of CVV, track data, or PIN',
'PAN encrypted when stored',
'PAN masked when displayed',
'Encryption keys properly managed'
],
'vulnerability_management': [
'Anti-virus installed and updated',
'Secure development practices',
'Regular security patches',
'Vulnerability scanning performed'
],
'access_control': [
'Access restricted by role',
'Unique IDs for all users',
'Multi-factor authentication',
'Physical security measures'
],
'monitoring': [
'Audit logs enabled',
'Log review process',
'File integrity monitoring',
'Regular security testing'
],
'policy': [
'Security policy documented',
'Risk assessment performed',
'Security awareness training',
'Incident response plan'
]
}Resources
资源
- references/data-minimization.md: Never store prohibited data
- references/tokenization.md: Tokenization strategies
- references/encryption.md: Encryption requirements
- references/access-control.md: Role-based access
- references/audit-logging.md: Comprehensive logging
- assets/pci-compliance-checklist.md: Complete checklist
- assets/encrypted-storage.py: Encryption utilities
- scripts/audit-payment-system.sh: Compliance audit script
- references/data-minimization.md: 禁止存储的相关数据说明
- references/tokenization.md: 令牌化策略
- references/encryption.md: 加密要求
- references/access-control.md: 基于角色的访问控制
- references/audit-logging.md: 全面日志记录
- assets/pci-compliance-checklist.md: 完整检查清单
- assets/encrypted-storage.py: 加密工具
- scripts/audit-payment-system.sh: 合规审计脚本
Common Violations
常见违规行为
- Storing CVV: Never store card verification codes
- Unencrypted PAN: Card numbers must be encrypted at rest
- Weak Encryption: Use AES-256 or equivalent
- No Access Controls: Restrict who can access cardholder data
- Missing Audit Logs: Must log all access to payment data
- Insecure Transmission: Always use TLS 1.2+
- Default Passwords: Change all default credentials
- No Security Testing: Regular penetration testing required
- 存储CVV:禁止存储卡验证码
- 未加密的PAN:卡号在静态存储时必须加密
- 弱加密:使用AES-256或等效加密算法
- 无访问控制:限制访问持卡人数据的人员
- 缺失审计日志:必须记录所有支付数据的访问行为
- 不安全传输:始终使用TLS 1.2+
- 默认密码:修改所有默认凭据
- 无安全测试:需要定期进行渗透测试
Reducing PCI Scope
缩小PCI合规范围
- Use Hosted Payments: Stripe Checkout, PayPal, etc.
- Tokenization: Replace card data with tokens
- Network Segmentation: Isolate cardholder data environment
- Outsource: Use PCI-compliant payment processors
- No Storage: Never store full card details
By minimizing systems that touch card data, you reduce compliance burden significantly.
- 使用托管支付服务:如Stripe Checkout、PayPal等
- 令牌化:用令牌替换卡数据
- 网络分段:隔离持卡人数据环境
- 外包处理:使用符合PCI合规的支付处理器
- 不存储数据:绝不存储完整的卡信息
通过减少接触卡数据的系统数量,可以显著降低合规负担。