PCIDSS合规规划Skill pci-dss-compliance

本技能提供支付卡行业数据安全标准(PCI DSS)合规的全面指导,帮助企业在开发支付系统前进行合规规划,包括范围减少策略、SAQ选择和安全控制实现。关键词:PCI DSS、合规、支付卡安全、范围减少、SAQ、安全控制。

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

name: pci-dss-compliance description: PCI DSS合规规划,用于支付卡处理,包括范围减少、SAQ选择和安全控制 allowed-tools: 读取、全局搜索、grep、写入、编辑、任务

PCI DSS合规规划

在开发开始前提供支付卡行业数据安全标准合规的全面指导。

何时使用此技能

  • 构建电子商务或支付处理系统
  • 与支付网关或处理器集成
  • 设计范围减少策略(令牌化、P2PE)
  • 为您的业务选择适当的SAQ
  • 准备PCI DSS评估

PCI DSS基础

持卡人数据元素

数据元素 描述 允许存储? 所需保护
PAN 主账号(16位数字) 是,如果受保护 渲染不可读
持卡人姓名 卡上姓名 按需求保护
服务代码 3-4位代码 按需求保护
过期日期 月/年 按需求保护
CVV/CVC 卡验证值 认证后永不 不适用 - 永不存储
PIN/PIN块 个人识别码 认证后永不 不适用 - 永不存储
完整磁道数据 磁条数据 认证后永不 不适用 - 永不存储

12项要求(PCI DSS 4.0)

目标1:构建和维护安全的网络和系统
  1. 安装和维护网络安全控制
  2. 对所有系统组件应用安全配置

目标2:保护账户数据
  3. 保护存储的账户数据
  4. 在传输期间使用强加密保护持卡人数据

目标3:维护漏洞管理程序
  5. 保护所有系统和网络免受恶意软件侵害
  6. 开发和维护安全的系统和软件

目标4:实施强访问控制措施
  7. 根据业务需要限制对持卡人数据的访问
  8. 识别用户并验证对系统组件的访问
  9. 限制对持卡人数据的物理访问

目标5:定期监控和测试网络
  10. 记录和监控对所有系统组件和持卡人数据的访问
  11. 定期测试系统和网络的安全性

目标6:维护信息安全政策
  12. 通过组织政策和程序支持信息安全

范围减少策略

理解PCI范围

在范围内: 任何存储、处理或传输持卡人数据的系统,或连接到此类系统的系统。

范围减少目标: 最小化处理原始持卡人数据的系统。

策略1:令牌化

用非敏感令牌替换PAN;处理器存储实际卡数据。

// 客户端令牌化流程
public class PaymentTokenization
{
    private readonly IPaymentGateway _gateway;

    public async Task<PaymentResult> ProcessPayment(
        string clientToken, // 通过网关的JS在浏览器中创建的令牌
        decimal amount,
        string currency,
        CancellationToken ct)
    {
        // 服务器从不看到原始卡数据 - 仅令牌
        var request = new ChargeRequest
        {
            Token = clientToken,
            Amount = amount,
            Currency = currency,
            MerchantReference = Guid.NewGuid().ToString()
        };

        // 在网关处用令牌交换支付
        var result = await _gateway.Charge(request, ct);

        // 仅存储交易参考,永不存储卡数据
        return new PaymentResult
        {
            TransactionId = result.TransactionId,
            Status = result.Status,
            // 存储令牌用于定期支付(如果存入库)
            VaultToken = result.VaultToken
        };
    }
}

// 范围:仅网关SDK在范围内,不是整个应用程序

策略2:托管支付页面(重定向)

客户在处理器页面上输入卡数据;您永不处理卡数据。

public class HostedPaymentFlow
{
    private readonly IHostedPaymentProvider _provider;

    public async Task<string> CreatePaymentSession(
        Order order,
        CancellationToken ct)
    {
        var session = await _provider.CreateSession(new SessionRequest
        {
            Amount = order.Total,
            Currency = order.Currency,
            SuccessUrl = $"https://example.com/payment/success?order={order.Id}",
            CancelUrl = $"https://example.com/payment/cancel?order={order.Id}",
            WebhookUrl = "https://example.com/api/payment-webhook",
            Metadata = new Dictionary<string, string>
            {
                ["order_id"] = order.Id.ToString()
            }
        }, ct);

        // 重定向客户到处理器的托管页面
        return session.RedirectUrl;
    }

    // Webhook接收支付确认 - 无卡数据
    public async Task HandleWebhook(PaymentWebhook webhook, CancellationToken ct)
    {
        // 验证webhook签名
        if (!_provider.VerifySignature(webhook))
            throw new SecurityException("无效的webhook签名");

        // 更新订单状态
        var orderId = Guid.Parse(webhook.Metadata["order_id"]);
        await _orderService.MarkPaid(orderId, webhook.TransactionId, ct);
    }
}

策略3:iFrame/嵌入式字段

卡字段由处理器托管,但显示在您的页面上。

<!-- Stripe Elements示例 - 字段由Stripe托管 -->
<form id="payment-form">
    <div id="card-element">
        <!-- Stripe在此注入安全卡输入 -->
    </div>
    <button type="submit">支付</button>
</form>

<script>
// 卡数据永不触及您的服务器
const stripe = Stripe('pk_live_xxx');
const elements = stripe.elements();
const cardElement = elements.create('card');
cardElement.mount('#card-element');

form.addEventListener('submit', async (e) => {
    e.preventDefault();
    // 客户端创建令牌,发送到您的服务器
    const {token} = await stripe.createToken(cardElement);
    // 仅令牌发送到您的服务器
    await fetch('/api/payment', {
        method: 'POST',
        body: JSON.stringify({ token: token.id })
    });
});
</script>

策略4:点对点加密(P2PE)

硬件在刷卡时加密卡数据;仅在处理器处解密。

卡刷卡 → P2PE终端 → 加密 → 您的系统 → 处理器
                                        (无法解密)

优点:
- 您的系统仅处理加密数据
- 范围大幅减少
- 需要P2PE验证解决方案

范围减少比较

策略 您的PCI范围 SAQ类型 复杂度
存储原始卡 全环境 D 非常高
令牌化(API) 令牌处理系统 A-EP或D 中等
iFrame/托管字段 最小(网页) A或A-EP
重定向到处理器 无(仅推荐) A 非常低
P2PE硬件 终端+网络 P2PE

SAQ选择指南

SAQ类型概述

SAQ 适用对象 要求 问题数
A 电子商务,所有卡功能外包 您的系统无CHD ~24
A-EP 电子商务,网站影响卡安全 iFrame/JS方法 ~191
B 仅压卡/独立拨号终端 无电子存储 ~41
B-IP 独立IP连接终端 无电子存储 ~82
C 互联网连接系统上的支付应用 无电子存储 ~160
C-VT 虚拟终端,无电子存储 基于Web,无存储 ~79
D 所有其他商户 全要求 ~329
D(SP) 服务提供商 全要求 ~400+
P2PE 使用验证P2PE解决方案 终端+P2PE ~33

决策树

您是否以电子方式存储/处理/传输CHD?
├─ 否:您是否仅为电子商务?
│   ├─ 是:所有卡功能外包?
│   │   ├─ 是 → SAQ A
│   │   └─ 否:网站控制重定向/iFrame?
│   │       ├─ 是 → SAQ A-EP
│   │       └─ 否 → SAQ D
│   └─ 否:仅卡在场?
│       ├─ 压卡/独立拨号 → SAQ B
│       ├─ 独立IP终端 → SAQ B-IP
│       ├─ P2PE验证解决方案 → SAQ P2PE
│       └─ 其他 → SAQ C或D
└─ 是: → SAQ D(全评估)

安全控制实现

要求3:保护存储的账户数据

// PAN掩码(仅显示前6位、后4位)
public static class PanMasking
{
    public static string Mask(string pan)
    {
        if (string.IsNullOrEmpty(pan) || pan.Length < 13)
            return pan;

        // 前6位(BIN)+ 掩码中间 + 后4位
        var first6 = pan[..6];
        var last4 = pan[^4..];
        var maskedLength = pan.Length - 10;

        return $"{first6}{new string('*', maskedLength)}{last4}";
    }

    // 示例:4111111111111111 → 411111******1111
}

// 存储PAN的强加密(当需要存储时)
public class PanEncryption
{
    private readonly IKeyManagement _keyManager;

    public async Task<EncryptedPan> Encrypt(string pan, CancellationToken ct)
    {
        // 使用AES-256最低
        var key = await _keyManager.GetCurrentKey("pan-encryption", ct);

        using var aes = Aes.Create();
        aes.Key = key.KeyMaterial;
        aes.GenerateIV();

        using var encryptor = aes.CreateEncryptor();
        var plainBytes = Encoding.UTF8.GetBytes(pan);
        var encryptedBytes = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length);

        return new EncryptedPan
        {
            EncryptedData = Convert.ToBase64String(encryptedBytes),
            KeyId = key.KeyId,
            IV = Convert.ToBase64String(aes.IV)
        };
    }
}

要求4:加密传输

// 强制执行TLS 1.2+
public static class TlsConfiguration
{
    public static void ConfigureSecureDefaults()
    {
        // 禁用旧协议
        ServicePointManager.SecurityProtocol =
            SecurityProtocolType.Tls12 |
            SecurityProtocolType.Tls13;
    }
}

// ASP.NET Core配置
public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        builder.WebHost.ConfigureKestrel(options =>
        {
            options.ConfigureHttpsDefaults(https =>
            {
                https.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13;
            });
        });

        // ... 其余配置
    }
}

要求8:认证

// CDE访问的多因素认证
public class PciMfaPolicy
{
    public bool RequiresMfa(string userId, string resourcePath)
    {
        // 所有CDE访问需要MFA
        var cdeResources = new[]
        {
            "/admin/payments",
            "/api/transactions",
            "/reports/cardholder"
        };

        return cdeResources.Any(r =>
            resourcePath.StartsWith(r, StringComparison.OrdinalIgnoreCase));
    }
}

// 密码策略(PCI DSS 4.0)
public class PciPasswordPolicy : IPasswordPolicy
{
    public PasswordRequirements GetRequirements()
    {
        return new PasswordRequirements
        {
            MinimumLength = 12,          // 4.0从7增加
            RequireComplexity = true,    // 多字符类型
            MaxAgeInDays = 90,           // 每90天强制更改
            HistoryCount = 4,            // 不能重用最后4个
            LockoutThreshold = 10,       // 10次失败后锁定
            LockoutDurationMinutes = 30,
            IdleTimeoutMinutes = 15      // CDE访问会话超时
        };
    }
}

要求10:日志和监控

// PCI合规审计日志
public class PciAuditLogger
{
    private readonly ILogger _logger;
    private readonly TimeProvider _timeProvider;

    public void LogCdeAccess(CdeAccessEvent accessEvent)
    {
        // PCI要求:谁、什么、何时、何地、成功/失败
        var entry = new AuditEntry
        {
            Timestamp = _timeProvider.GetUtcNow(),
            UserId = accessEvent.UserId,
            UserName = accessEvent.UserName,
            EventType = accessEvent.EventType.ToString(),
            Resource = accessEvent.Resource,
            Action = accessEvent.Action,
            SourceIp = accessEvent.SourceIp,
            Success = accessEvent.Success,
            Details = accessEvent.Details
        };

        // 永不记录实际卡数据
        _logger.LogInformation(
            "CDE_ACCESS: 用户={UserId} 动作={Action} 资源={Resource} 成功={Success} IP={SourceIp}",
            entry.UserId,
            entry.Action,
            entry.Resource,
            entry.Success,
            entry.SourceIp);

        // 保留日志至少1年
        // 3个月内立即可用
    }

    public void LogSecurityEvent(SecurityEvent secEvent)
    {
        // 安全事件记录:
        // - 所有对CHD的访问
        // - 管理员/root的所有操作
        // - 所有无效访问尝试
        // - 系统对象的创建/删除
        // - 审计日志的初始化
        // - 审计日志的停止/暂停
    }
}

网络分段

CDE网络隔离

┌─────────────────────────────────────────────────────────────┐
│                     企业网络                        │
│  ┌──────────────────────────────────────────────────────┐   │
│  │              持卡人数据环境             │   │
│  │  ┌──────────┐    ┌──────────┐    ┌──────────┐       │   │
│  │  │ 支付  │    │ 数据库 │    │   管理  │       │   │
│  │  │  服务器  │────│  服务器  │────│  跳板机  │       │   │
│  │  └──────────┘    └──────────┘    └──────────┘       │   │
│  │       │                               │              │   │
│  │       │ ← 防火墙/ACLs →            │              │   │
│  └───────┼──────────────────────────────┼──────────────┘   │
│          │                               │                  │
│    ┌─────▼─────┐                   ┌─────▼─────┐           │
│    │  网页应用  │                   │   管理    │           │
│    │ (无CHD)  │                   │  工作站   │           │
│    └───────────┘                   └───────────┘           │
└─────────────────────────────────────────────────────────────┘

CDE防火墙规则

# 示例防火墙规则
CDE_入站:
  - 允许:来自Web层的支付API(443)
  - 允许:仅来自跳板机的SSH(22)
  - 允许:仅来自支付服务器的数据库(5432)
  - 拒绝:所有其他

CDE_出站:
  - 允许:支付处理器API(443)
  - 允许:到批准服务器的NTP(123)
  - 允许:到SIEM的Syslog(514)
  - 拒绝:所有其他

PCI合规清单

开发前

  • [ ] 识别所有支付流程
  • [ ] 选择范围减少策略
  • [ ] 选择适当的SAQ类型
  • [ ] 建立CDE边界
  • [ ] 审查供应商PCI合规性(AOC)

架构与设计

  • [ ] 文档化网络分段
  • [ ] 定义加密策略(存储和传输)
  • [ ] 设计访问控制模型
  • [ ] 计划审计日志方法
  • [ ] 确保无CVV/PIN存储

开发

  • [ ] 永不记录卡数据
  • [ ] 实施仅TLS 1.2+
  • [ ] 应用PAN掩码用于显示
  • [ ] 强制CDE访问的MFA
  • [ ] 遵循安全编码(要求6)

测试与评估

  • [ ] 漏洞扫描(内部/外部季度)
  • [ ] 渗透测试(年度)
  • [ ] 分段测试(如果分段)
  • [ ] 应用安全测试

交叉参考

  • 安全框架security-frameworks 用于控制映射
  • 数据分类data-classification 用于CHD处理
  • 许可证合规license-compliance 用于支付SDK条款

资源