pci-compliance

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

PCI 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

构建并维护安全网络

  1. Install and maintain firewall configuration
  2. Don't use vendor-supplied defaults for passwords
  1. 安装并维护防火墙配置
  2. 不要使用供应商提供的默认密码

Protect Cardholder Data

保护持卡人数据

  1. Protect stored cardholder data
  2. Encrypt transmission of cardholder data across public networks
  1. 保护存储的持卡人数据
  2. 在公共网络上加密传输持卡人数据

Maintain Vulnerability Management

维护漏洞管理计划

  1. Protect systems against malware
  2. Develop and maintain secure systems and applications
  1. 保护系统免受恶意软件侵害
  2. 开发并维护安全的系统和应用程序

Implement Strong Access Control

实施严格的访问控制措施

  1. Restrict access to cardholder data by business need-to-know
  2. Identify and authenticate access to system components
  3. Restrict physical access to cardholder data
  1. 根据业务需求限制对持卡人数据的访问
  2. 识别并验证对系统组件的访问权限
  3. 限制对持卡人数据的物理访问

Monitor and Test Networks

监控和测试网络

  1. Track and monitor all access to network resources and cardholder data
  2. Regularly test security systems and processes
  1. 跟踪并监控对网络资源和持卡人数据的所有访问
  2. 定期测试安全系统和流程

Maintain Information Security Policy

维护信息安全政策

  1. Maintain a policy that addresses information security
  1. 制定并维护信息安全政策

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
undefined
python
undefined

NEVER 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}")
undefined
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}")
undefined

Tokenization

令牌化

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

undefined
undefined

Data in Transit

传输数据加密

python
undefined
python
undefined

Always 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)
undefined
from flask_talisman import Talisman Talisman(app, force_https=True)
undefined

Access 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
    pass
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
    pass

Audit 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')
undefined
audit = PCIAuditLogger() audit.log_access(user_id=123, resource='payment_methods', action='read', result='success')
undefined

Security 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
    pass
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
    pass

PCI 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

常见违规行为

  1. Storing CVV: Never store card verification codes
  2. Unencrypted PAN: Card numbers must be encrypted at rest
  3. Weak Encryption: Use AES-256 or equivalent
  4. No Access Controls: Restrict who can access cardholder data
  5. Missing Audit Logs: Must log all access to payment data
  6. Insecure Transmission: Always use TLS 1.2+
  7. Default Passwords: Change all default credentials
  8. No Security Testing: Regular penetration testing required
  1. 存储CVV:禁止存储卡验证码
  2. 未加密的PAN:卡号在静态存储时必须加密
  3. 弱加密:使用AES-256或等效加密算法
  4. 无访问控制:限制访问持卡人数据的人员
  5. 缺失审计日志:必须记录所有支付数据的访问行为
  6. 不安全传输:始终使用TLS 1.2+
  7. 默认密码:修改所有默认凭据
  8. 无安全测试:需要定期进行渗透测试

Reducing PCI Scope

缩小PCI合规范围

  1. Use Hosted Payments: Stripe Checkout, PayPal, etc.
  2. Tokenization: Replace card data with tokens
  3. Network Segmentation: Isolate cardholder data environment
  4. Outsource: Use PCI-compliant payment processors
  5. No Storage: Never store full card details
By minimizing systems that touch card data, you reduce compliance burden significantly.
  1. 使用托管支付服务:如Stripe Checkout、PayPal等
  2. 令牌化:用令牌替换卡数据
  3. 网络分段:隔离持卡人数据环境
  4. 外包处理:使用符合PCI合规的支付处理器
  5. 不存储数据:绝不存储完整的卡信息
通过减少接触卡数据的系统数量,可以显著降低合规负担。