Skip to main content
Back to Blog
15 October 202414 min read

PCI Compliance in Practice: Building Secure Payment Integrations

SecurityPCI-DSSPaymentsCompliance

Real-world experience implementing PCI-compliant payment systems. IVR integration, tokenization strategies, and audit preparation.


PCI Compliance in Practice: Building Secure Payment Integrations

At Interflora, we achieved PCI-DSS Level 1 compliance for a telesales platform processing millions of transactions annually. The journey taught me that PCI compliance isn't about checking boxes—it's about fundamentally rethinking how cardholder data flows through your systems. Here's a practical guide based on that experience.

Understanding PCI-DSS Scope

Compliance Levels

LevelTransaction VolumeRequirements
Level 16M+ annuallyOn-site audit by QSA
Level 21M-6M annuallySAQ-D or on-site audit
Level 320K-1M annuallySAQ-D
Level 4<20K annuallySAQ (varies)

The Scope Equation

Everything that stores, processes, or transmits cardholder data is in scope. This includes:

  • Systems directly handling card numbers
  • Systems connected to those systems
  • Systems that could affect the security of those systems

Critical insight: The most effective PCI strategy is scope reduction, not scope protection.

Scope Reduction Strategies

Strategy 1: Tokenization

Replace actual card numbers with tokens before they enter your systems:

WITHOUT Tokenization:
Customer → Your App → Your DB → Payment Processor
          [PAN data flows through everything]
          [Everything is in PCI scope]

WITH Tokenization:
Customer → Payment Processor → Your App → Your DB
          [Card entered at processor]
          [Your systems only see tokens]
          [Minimal PCI scope]

Implementation approach:

// Frontend: Direct card entry to payment provider const stripe = await loadStripe(publishableKey); const elements = stripe.elements(); const cardElement = elements.create('card'); // Card data goes directly to Stripe, never touches your server const { token, error } = await stripe.createToken(cardElement); // Your backend only receives the token await fetch('/api/checkout', { method: 'POST', body: JSON.stringify({ paymentToken: token.id, // Safe to store orderId: 'order-123' }) });

Strategy 2: Hosted Payment Pages

Redirect card entry entirely to a payment processor's hosted page:

Customer → Your Checkout → Processor Hosted Page → Processor
               ↓                    ↓
          Order details         Card entry
          (in scope: minimal)   (in scope: processor)

Considerations:

ApproachUX ImpactScope ReductionControl
Hosted page (redirect)More frictionMaximumMinimal
Hosted iframeModerateHighModerate
Hosted fieldsMinimalHighGood
Direct integrationNoneNoneMaximum

Strategy 3: IVR for Telesales

The Interflora solution: agent-assisted IVR payment capture.

The problem: Call center agents traditionally hear and enter card numbers, putting the entire call center environment in PCI scope.

The solution: Mid-call IVR handoff

Traditional Telesales:
Agent → Hears card number → Enters in system → Processes payment
        [PCI scope: agent environment, agent systems, workstations,
         network, call recordings, training materials...]

IVR-Assisted:
Agent → Transfers to IVR → Customer enters card via DTMF → IVR processes
        [Agent remains on line but audio is muted during card entry]
        [PCI scope: IVR system only]

Technical implementation:

Call Flow:
1. Agent takes order details
2. Agent initiates payment transfer: "I'll now transfer you to our secure payment line"
3. System places agent on silent hold (can monitor, cannot hear DTMF)
4. IVR prompts: "Please enter your 16-digit card number"
5. Customer enters card via phone keypad
6. IVR captures and tokenizes in real-time
7. Payment processed, result returned
8. Agent reconnected: "Your payment was successful"

Key requirements:

  • DTMF tones suppressed from agent audio
  • No card data in call recordings
  • IVR system isolated in separate network segment
  • Agent screens show only masked data (****1234)

Technical Controls Implementation

Network Segmentation

Create a Cardholder Data Environment (CDE) with strict boundaries:

Corporate Network                    CDE (Cardholder Data Environment)
┌──────────────────────┐            ┌──────────────────────┐
│                      │            │                      │
│  App Servers         │   FW/IDS   │  Payment Gateway     │
│  Web Servers         │ ◄────────► │  IVR System          │
│  Databases (no PAN)  │            │  Token Vault         │
│                      │            │                      │
└──────────────────────┘            └──────────────────────┘

Network Rules:
- Only specific ports/protocols allowed between zones
- All traffic logged and monitored
- No direct internet access from CDE
- Jump host required for administrative access

Encryption Requirements

In Transit:

- TLS 1.2+ for all connections
- Strong cipher suites only
- Certificate pinning for payment APIs
- No SSL/early TLS (deprecated)

At Rest:

// Key management with HSM or cloud KMS const encryptPAN = async (pan: string): Promise<string> => { const key = await kms.getKey('pan-encryption-key'); // AES-256-GCM encryption const iv = crypto.randomBytes(16); const cipher = crypto.createCipheriv('aes-256-gcm', key, iv); let encrypted = cipher.update(pan, 'utf8', 'base64'); encrypted += cipher.final('base64'); const authTag = cipher.getAuthTag(); // Store: IV + AuthTag + Encrypted data return Buffer.concat([iv, authTag, Buffer.from(encrypted, 'base64')]).toString('base64'); };

Key management principles:

  • Dual control for key creation
  • Split knowledge for key custodians
  • Annual key rotation (minimum)
  • Secure key destruction procedures

Access Control

Role-Based Access Control (RBAC):

Role: payment_admin
├── Can: View masked PANs, manage configurations
├── Cannot: View full PANs, export data
└── MFA: Required

Role: support_agent
├── Can: View last 4 digits, process refunds (with supervisor)
├── Cannot: View full PANs, change configurations
└── MFA: Required

Role: developer
├── Can: Access non-production environments
├── Cannot: Access production CDE, view any PAN data
└── MFA: Required for VPN

All Access:
- Unique user IDs (no shared accounts)
- Automatic lockout after 6 failed attempts
- 90-day password rotation
- Session timeout: 15 minutes idle

Logging and Monitoring

PCI DSS Requirement 10 mandates comprehensive logging:

// Structured security logging interface SecurityAuditLog { timestamp: string; eventType: 'access' | 'modify' | 'delete' | 'authenticate'; userId: string; sourceIp: string; resource: string; action: string; result: 'success' | 'failure'; details: Record<string, unknown>; } // Log all access to cardholder data const logCardDataAccess = async ( userId: string, action: string, maskedPan: string ): Promise<void> => { await auditLogger.log({ timestamp: new Date().toISOString(), eventType: 'access', userId, sourceIp: getClientIp(), resource: 'cardholder_data', action, result: 'success', details: { maskedPan, // Never log full PAN sessionId: getSessionId() } }); };

Log retention:

  • Minimum 1 year retention
  • 3 months immediately accessible
  • Tamper-evident storage
  • Regular integrity verification

Audit Preparation

The QSA Visit

A Qualified Security Assessor (QSA) audit involves:

  1. Document Review: Policies, procedures, network diagrams
  2. Technical Testing: Vulnerability scans, penetration tests
  3. Interviews: Staff at all levels about security procedures
  4. Evidence Collection: Logs, configurations, access records

Evidence Organization

PCI Evidence Repository:
├── policies/
│   ├── information-security-policy.pdf
│   ├── access-control-policy.pdf
│   └── incident-response-plan.pdf
├── network/
│   ├── network-diagram-current.vsdx
│   ├── data-flow-diagram.vsdx
│   └── firewall-rules-export.csv
├── testing/
│   ├── quarterly-vuln-scans/
│   ├── annual-pentest-report.pdf
│   └── segmentation-test-results.pdf
├── access/
│   ├── user-access-review-Q1.xlsx
│   ├── terminated-users-log.csv
│   └── privilege-access-list.xlsx
└── training/
    ├── security-awareness-completion.csv
    └── training-materials/

Continuous Compliance

Don't treat PCI as an annual event:

Monthly:
- Review access logs for anomalies
- Verify terminated user access removed
- Check for unpatched systems

Quarterly:
- ASV vulnerability scans
- Firewall rule review
- Wireless network scans (if applicable)

Annually:
- Penetration testing
- Risk assessment update
- Policy review and update
- Security awareness training

Common Pitfalls

1. Scope Creep

Problem: Systems gradually connect to CDE, expanding scope

Solution: Change management requires PCI impact assessment

2. Test Data Issues

Problem: Using production card data in test environments

Solution: Data masking and synthetic test data

// Generate valid test card numbers (Luhn-valid, non-real) const testCards = { visa: '4111111111111111', mastercard: '5500000000000004', amex: '340000000000009' };

3. Logging Sensitive Data

Problem: Full PANs appearing in logs, error messages, or debug output

Solution: Mask at the source

const maskPan = (pan: string): string => { if (!pan || pan.length < 13) return '****'; return pan.slice(0, 6) + '****' + pan.slice(-4); }; // Ensure masking in all log contexts logger.addTransform((log) => { return JSON.parse(JSON.stringify(log, (key, value) => { if (key.toLowerCase().includes('pan') || key.toLowerCase().includes('card')) { return typeof value === 'string' ? maskPan(value) : value; } return value; })); });

4. Third-Party Risk

Problem: Assuming vendors handle PCI compliance

Solution: Validate and monitor third-party compliance

  • Request AOC (Attestation of Compliance) annually
  • Include PCI requirements in contracts
  • Monitor for security incidents at vendors

Key Takeaways

  1. Scope reduction is your best strategy: Use tokenization, hosted pages, or IVR to minimize what's in your PCI scope
  2. Network segmentation is foundational: Isolate the CDE with strict access controls
  3. Encryption requires key management: Strong encryption is useless without proper key handling
  4. Logging enables detection: Comprehensive, tamper-evident logs are essential
  5. Continuous compliance beats annual panic: Monthly and quarterly activities prevent audit surprises
  6. Third parties share responsibility: Validate their compliance and monitor for issues
  7. Document everything: If it's not documented, it didn't happen (according to auditors)

PCI compliance is demanding, but it forces you to think systematically about data security. The disciplines you build for PCI—scope management, access control, logging, and continuous monitoring—improve your security posture far beyond payment processing.

Share this article