PCI合规Skill pci-compliance

PCI合规技能用于确保支付卡数据的安全处理和支付系统的合规性,实现PCI DSS(支付卡行业数据安全标准)要求。它包括构建安全网络、保护持卡人数据、实施访问控制、监控和测试网络、维护信息安全政策。关键词:PCI DSS、支付安全、数据加密、令牌化、访问控制、审计日志、合规审计、支付卡行业。

合规 0 次安装 0 次浏览 更新于 3/22/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:1-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 = os.urandom(12)

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

        # 返回随机数 + 密文
        return nonce + ciphertext

    def decrypt(self, encrypted_data):
        """解密数据。"""
        # 提取随机数和密文
        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. 不存储:绝不存储完整卡详情

通过最小化接触卡数据的系统,可以显著减少合规负担。