PCI合规技能Skill pci-compliance

PCI合规技能用于实现支付卡行业数据安全标准(PCI DSS)的合规要求,确保支付卡数据的安全处理,涵盖网络安全、数据加密、访问控制和审计等关键方面。适用于支付系统开发、安全审计和合规管理。关键词:PCI DSS、合规性、支付安全、数据加密、网络安全、审计。

合规 0 次安装 0 次浏览 更新于 3/16/2026

name: pci-compliance description: 实施PCI DSS合规要求,用于安全处理支付卡数据和支付系统。在确保支付处理安全、实现PCI合规或实施支付卡安全措施时使用。

PCI合规性

掌握PCI DSS(支付卡行业数据安全标准)合规性,用于安全支付处理和处理持卡人数据。

何时使用此技能

  • 构建支付处理系统
  • 处理信用卡信息
  • 实施安全支付流程
  • 进行PCI合规审计
  • 减少PCI合规范围
  • 实施令牌化和加密
  • 准备PCI DSS评估

PCI DSS要求(12项核心要求)

建立和维护安全网络

  1. 安装和维护防火墙配置
  2. 不使用供应商提供的默认密码

保护持卡人数据

  1. 保护存储的持卡人数据
  2. 在公共网络上加密传输持卡人数据

维护漏洞管理

  1. 保护系统免受恶意软件侵害
  2. 开发和维护安全系统和应用

实施强访问控制

  1. 按业务需知限制对持卡人数据的访问
  2. 识别和验证对系统组件的访问
  3. 限制对持卡人数据的物理访问

监控和测试网络

  1. 跟踪和监控所有对网络资源和持卡人数据的访问
  2. 定期测试安全系统和流程

维护信息安全政策

  1. 维护解决信息安全的政策

合规级别

级别1:> 600万笔交易/年(需要年度ROC) 级别2:100万-600万笔交易/年(年度SAQ) 级别3:20,000-100万笔电子商务交易/年 级别4:< 20,000笔电子商务或< 100万笔总交易

数据最小化(永不存储)

# 永不存储这些
PROHIBITED_DATA = {
    'full_track_data': '磁条数据',
    'cvv': '卡片验证码/值',
    'pin': 'PIN或PIN块'
}

# 可以存储(如果加密)
ALLOWED_DATA = {
    'pan': '主账号(卡号)',
    'cardholder_name': '卡片持有者姓名',
    'expiration_date': '卡片过期日期',
    'service_code': '服务代码'
}

class PaymentData:
    """安全支付数据处理。"""

    def __init__(self):
        self.prohibited_fields = ['cvv', 'cvv2', 'cvc', 'pin']

    def sanitize_log(self, data):
        """从日志中移除敏感数据。"""
        sanitized = data.copy()

        # 掩码PAN
        if 'card_number' in sanitized:
            card = sanitized['card_number']
            sanitized['card_number'] = f"{card[:6]}{'*' * (len(card) - 10)}{card[-4:]}"

        # 移除禁止数据
        for field in self.prohibited_fields:
            sanitized.pop(field, None)

        return sanitized

    def validate_no_prohibited_storage(self, data):
        """确保不存储禁止数据。"""
        for field in self.prohibited_fields:
            if field in data:
                raise SecurityError(f"尝试存储禁止字段:{field}")

令牌化

使用支付处理器令牌

import stripe

class TokenizedPayment:
    """使用令牌处理支付(服务器上无卡数据)。"""

    @staticmethod
    def create_payment_method_token(card_details):
        """从卡详情创建令牌(仅客户端)。"""
        # 这应仅使用STRIPE.JS在客户端完成
        # 永远不要将卡详情发送到服务器

        """
        // 前端JavaScript
        const stripe = Stripe('pk_...');

        const {token, error} = await stripe.createToken({
            card: {
                number: '4242424242424242',
                exp_month: 12,
                exp_year: 2024,
                cvc: '123'
            }
        });

        // 发送token.id到服务器(不是卡详情)
        """
        pass

    @staticmethod
    def charge_with_token(token_id, amount):
        """使用令牌收费(服务器端)。"""
        # 服务器只看到令牌,从来看不到卡号
        stripe.api_key = "sk_..."

        charge = stripe.Charge.create(
            amount=amount,
            currency="usd",
            source=token_id,  # 令牌代替卡详情
            description="支付"
        )

        return charge

    @staticmethod
    def store_payment_method(customer_id, payment_method_token):
        """将支付方法存储为令牌以供将来使用。"""
        stripe.Customer.modify(
            customer_id,
            source=payment_method_token
        )

        # 仅在数据库中存储customer_id和payment_method_id
        # 永远不要存储实际卡详情
        return {
            'customer_id': customer_id,
            'has_payment_method': True
            # 不要存储:卡号、CVV等
        }

自定义令牌化(高级)

import secrets
from cryptography.fernet import Fernet

class TokenVault:
    """卡数据的安全令牌保险库(如果必须存储)。"""

    def __init__(self, encryption_key):
        self.cipher = Fernet(encryption_key)
        self.vault = {}  # 在生产中:使用加密数据库

    def tokenize(self, card_data):
        """将卡数据转换为令牌。"""
        # 生成安全随机令牌
        token = secrets.token_urlsafe(32)

        # 加密卡数据
        encrypted = self.cipher.encrypt(json.dumps(card_data).encode())

        # 存储令牌 -> 加密数据映射
        self.vault[token] = encrypted

        return token

    def detokenize(self, token):
        """从令牌检索卡数据。"""
        encrypted = self.vault.get(token)
        if not encrypted:
            raise ValueError("未找到令牌")

        # 解密
        decrypted = self.cipher.decrypt(encrypted)
        return json.loads(decrypted.decode())

    def delete_token(self, token):
        """从保险库移除令牌。"""
        self.vault.pop(token, None)

加密

静态数据

from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os

class EncryptedStorage:
    """使用AES-256-GCM加密静态数据。"""

    def __init__(self, encryption_key):
        """使用256位密钥初始化。"""
        self.key = encryption_key  # 必须为32字节

    def encrypt(self, plaintext):
        """加密数据。"""
        # 生成随机nonce
        nonce = os.urandom(12)

        # 加密
        aesgcm = AESGCM(self.key)
        ciphertext = aesgcm.encrypt(nonce, plaintext.encode(), None)

        # 返回nonce + ciphertext
        return nonce + ciphertext

    def decrypt(self, encrypted_data):
        """解密数据。"""
        # 提取nonce和ciphertext
        nonce = encrypted_data[:12]
        ciphertext = encrypted_data[12:]

        # 解密
        aesgcm = AESGCM(self.key)
        plaintext = aesgcm.decrypt(nonce, ciphertext, None)

        return plaintext.decode()

# 用法
storage = EncryptedStorage(os.urandom(32))
encrypted_pan = storage.encrypt("4242424242424242")
# 将encrypted_pan存储在数据库中

传输数据

# 始终使用TLS 1.2或更高版本
# Flask/Django示例
app.config['SESSION_COOKIE_SECURE'] = True  # 仅HTTPS
app.config['SESSION_COOKIE_HTTPONLY'] = True
app.config['SESSION_COOKIE_SAMESITE'] = 'Strict'

# 强制HTTPS
from flask_talisman import Talisman
Talisman(app, force_https=True)

访问控制

from functools import wraps
from flask import session

def require_pci_access(f):
    """装饰器以限制对持卡人数据的访问。"""
    @wraps(f)
    def decorated_function(*args, **kwargs):
        user = session.get('user')

        # 检查用户是否有PCI访问角色
        if not user or 'pci_access' not in user.get('roles', []):
            return {'error': '未经授权访问持卡人数据'}, 403

        # 记录访问尝试
        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():
    """检索支付方法(受限访问)。"""
    # 仅对具有pci_access角色的用户可访问
    pass

审计日志

import logging
from datetime import datetime

class PCIAuditLogger:
    """PCI合规审计日志。"""

    def __init__(self):
        self.logger = logging.getLogger('pci_audit')
        # 配置为写入安全、仅追加日志

    def log_access(self, user_id, resource, action, result):
        """记录对持卡人数据的访问。"""
        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):
        """记录认证尝试。"""
        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))

# 用法
audit = PCIAuditLogger()
audit.log_access(user_id=123, resource='payment_methods', action='read', result='success')

安全最佳实践

输入验证

import re

def validate_card_number(card_number):
    """验证卡号格式(Luhn算法)。"""
    # 移除空格和破折号
    card_number = re.sub(r'[\s-]', '', card_number)

    # 检查是否全数字
    if not card_number.isdigit():
        return False

    # Luhn算法
    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):
    """净化用户输入以防止注入。"""
    # 移除特殊字符
    # 根据预期格式验证
    # 为数据库查询转义
    pass

PCI DSS SAQ(自我评估问卷)

SAQ A(最少要求)

  • 使用托管支付页面的电子商务
  • 您的系统上无卡数据
  • ~20个问题

SAQ A-EP

  • 使用嵌入式支付表单的电子商务
  • 使用JavaScript处理卡数据
  • ~180个问题

SAQ D(最多要求)

  • 存储、处理或传输卡数据
  • 完整PCI DSS要求
  • ~300个问题

合规检查清单

PCI_COMPLIANCE_CHECKLIST = {
    'network_security': [
        '防火墙配置和维护',
        '无供应商默认密码',
        '网络分段实施'
    ],
    'data_protection': [
        '不存储CVV、磁条数据或PIN',
        'PAN存储时加密',
        'PAN显示时掩码',
        '加密密钥妥善管理'
    ],
    'vulnerability_management': [
        '安装和更新反病毒软件',
        '安全开发实践',
        '定期安全补丁',
        '执行漏洞扫描'
    ],
    'access_control': [
        '按角色限制访问',
        '所有用户唯一ID',
        '多因素认证',
        '物理安全措施'
    ],
    'monitoring': [
        '启用审计日志',
        '日志审查流程',
        '文件完整性监控',
        '定期安全测试'
    ],
    'policy': [
        '文档化安全政策',
        '执行风险评估',
        '安全意识培训',
        '事件响应计划'
    ]
}

资源

  • 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:合规审计脚本

常见违规

  1. 存储CVV:永不存储卡片验证码
  2. 未加密PAN:卡号存储时必须加密
  3. 弱加密:使用AES-256或等效
  4. 无访问控制:限制谁可以访问持卡人数据
  5. 缺少审计日志:必须记录所有对支付数据的访问
  6. 不安全传输:始终使用TLS 1.2+
  7. 默认密码:更改所有默认凭证
  8. 无安全测试:需要定期渗透测试

减少PCI范围

  1. 使用托管支付:Stripe Checkout、PayPal等
  2. 令牌化:用令牌替换卡数据
  3. 网络分段:隔离持卡人数据环境
  4. 外包:使用PCI合规支付处理器
  5. 不存储:永不存储完整卡详情

通过最小化接触卡数据的系统,显著降低合规负担。