Business Insights10 Desember 202514 min read

Navigating FinTech Compliance: Our PCI-DSS Certification Journey

Complete guide to achieving PCI-DSS compliance for payment platforms. Lessons from securing a system processing $50M+ annually with zero breaches.

DL

Dan Ramdani

Dan Labs

# Navigating FinTech Compliance: Our PCI-DSS Certification Journey

When building a payment platform processing $50M+ annually, compliance isn't optional—it's existential. Here's our complete PCI-DSS certification journey and practical implementation guide.

## What is PCI-DSS and Why It Matters

**PCI-DSS** (Payment Card Industry Data Security Standard) is a set of security standards ensuring all companies that accept, process, store or transmit credit card information maintain a secure environment.

**Why you need it**:
- Legal requirement for processing card payments
- Customers won't trust you without it
- Penalties for breach: $5K-100K per month + lawsuits
- Reputational damage is often unrecoverable

**Our Timeline**:
- Month 1-2: Gap assessment & planning
- Month 3-5: Implementation & remediation
- Month 6: QSA audit
- Month 7: Certification achieved ✅

**Cost**: $85K (security tools + consulting + audit fees)

## The 12 PCI-DSS Requirements (and How We Implemented)

### 1. Install and Maintain Firewall Configuration

**Requirement**: Protect cardholder data with firewalls.

**What we did**:
- AWS Security Groups: Whitelist only necessary IPs/ports
- Web Application Firewall (WAF): CloudFlare for DDoS protection
- Network segmentation: Cardholder Data Environment (CDE) isolated from other systems

**Implementation**:
```yaml
# AWS Security Group (Payment Service)
Inbound Rules:
- Port 443 (HTTPS): From API Gateway only
- Port 5432 (PostgreSQL): From App Server only
- SSH (22): From VPN only (specific IP ranges)

Outbound Rules:
- Port 443: To payment gateways only
- All other ports: Denied by default
```

**Cost**: $2K/month (CloudFlare Enterprise + AWS)

### 2. Don't Use Vendor-Supplied Defaults

**Requirement**: Change default passwords and remove unnecessary default accounts.

**What we did**:
- All servers provisioned with unique SSH keys (no passwords)
- Database admin usernames changed from "admin" to randomized
- Default ports changed (PostgreSQL from 5432 → 15432)
- All default accounts disabled

**Automated Check**:
```bash
# Script runs daily via cron
#!/bin/bash
# Check for default usernames
forbidden_users=("admin" "root" "postgres" "mysql")
for user in "${forbidden_users[@]}"; do
if id "$user" &>/dev/null; then
alert_security_team "Default user $user exists"
fi
done
```

### 3. Protect Stored Cardholder Data

**Requirement**: Encrypt cardholder data at rest.

**Critical**: We **never store full card numbers**. Instead, we use tokenization via Stripe/Xendit.

**Data Flow**:
```
User enters card → Frontend sends to Stripe → Stripe returns token
→ We store token only (useless if stolen)
```

**For PII we must store** (name, email, transaction amounts):
```javascript
// Encryption at rest using AES-256
const encryptPII = (data) => {
const cipher = crypto.createCipheriv(
'aes-256-gcm',
KEY_FROM_AWS_KMS, // Rotation policy: 90 days
IV
);
return cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
};
```

**Database encryption**: AWS RDS encrypted volumes (AES-256)

**Key management**: AWS KMS with automatic rotation every 90 days

### 4. Encrypt Transmission of Cardholder Data

**Requirement**: Encrypt cardholder data across public networks.

**What we did**:
- TLS 1.3 for all API endpoints (no TLS 1.0/1.1 allowed)
- Certificate pinning in mobile apps
- HSTS header: Force HTTPS always
- HTTP → HTTPS redirect at load balancer

**nginx config**:
```nginx
server {
listen 443 ssl http2;

# Strong TLS config
ssl_protocols TLSv1.3 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;

# HSTS: Force HTTPS for 1 year
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}
```

**Testing**: Monthly SSL Labs scan (Grade A+ required)

### 5. Use and Regularly Update Anti-Virus

**Requirement**: Protect systems against malware.

**What we did**:
- ClamAV on all servers (open-source antivirus)
- File upload scanning before storage
- Daily definition updates
- Weekly full system scans

**Automated scanning**:
```bash
# Scan all uploaded files
for file in /uploads/*; do
clamscan "$file"
if [ $? -ne 0 ]; then
rm "$file"
alert_security_team "Malware detected: $file"
fi
done
```

### 6. Develop and Maintain Secure Systems

**Requirement**: All systems and applications must be free from known vulnerabilities.

**What we did**:
- Monthly dependency audits: `npm audit`, `bundle audit`
- Automated patching for OS (AWS Systems Manager)
- Quarterly penetration testing by third-party
- Bug bounty program ($500-$5K per valid vulnerability)

**CI/CD Security Checks**:
```yaml
# GitLab CI pipeline
security_scan:
script:
- npm audit --audit-level=high # Fail on high/critical
- snyk test --severity-threshold=high
- trivy image --severity HIGH,CRITICAL
```

**Result**: Average time to patch critical vulnerabilities: 48 hours

### 7. Restrict Access to Cardholder Data

**Requirement**: Limit access to cardholder data on "need to know" basis.

**What we did**:
- Role-Based Access Control (RBAC)
- Only 3 engineers have production DB access (encrypted, logged)
- MFA required for all system access
- Principle of least privilege

**Access Levels**:
```
Level 1 (Dev): Read access to non-PII data
Level 2 (Senior Dev): Read access to masked PII
Level 3 (Lead/DevOps): Full access, all actions logged
Level 4 (Auditor): Read-only access to everything
```

**Audit Log** (every access logged):
```json
{
"timestamp": "2025-12-10T14:23:11Z",
"user": "dan.ramdani@danlabs.co",
"action": "SELECT",
"table": "transactions",
"ip": "203.0.113.42",
"mfa_verified": true
}
```

### 8. Assign Unique ID to Each Person

**Requirement**: Each user must have unique credentials.

**What we did**:
- No shared accounts (each engineer has their own)
- SSO via Google Workspace
- MFA enforced (Authy/Google Authenticator)
- Session timeout: 15 minutes idle, 8 hours max

**MFA Implementation**:
```javascript
// Login requires password + TOTP code
const login = async (email, password, totpCode) => {
const user = await verifyPassword(email, password);
if (!user) throw new Error('Invalid credentials');

const totpValid = speakeasy.totp.verify({
secret: user.mfaSecret,
encoding: 'base32',
token: totpCode,
window: 1 // Allow 30-second clock skew
});

if (!totpValid) throw new Error('Invalid MFA code');

return generateJWT(user);
};
```

### 9. Restrict Physical Access

**Requirement**: Restrict physical access to cardholder data.

**What we did** (cloud-only infrastructure):
- AWS data centers (SOC 2 certified)
- No on-premise servers
- Physical access controls managed by AWS
- Office network isolated from production

**For office**:
- Disk encryption on all laptops (BitLocker/FileVault)
- No cardholder data on local machines (cloud-only access)
- Clean desk policy

### 10. Track and Monitor All Access

**Requirement**: Log all access to network resources and cardholder data.

**What we did**:
- Centralized logging: ELK stack (Elasticsearch, Logstash, Kibana)
- CloudTrail: All AWS API calls logged
- Application logs: Every DB query, API request, auth attempt
- Retention: 1 year minimum

**Critical logs**:
```javascript
// Every transaction logged
{
"event": "payment_processed",
"transaction_id": "txn_abc123",
"amount": 150000,
"currency": "IDR",
"user_id": "usr_xyz789",
"timestamp": "2025-12-10T14:30:00Z",
"ip_address": "203.0.113.42",
"user_agent": "Mozilla/5.0...",
"status": "success"
}
```

**Alerting rules**:
- Failed login >5 attempts in 10 min → alert
- DB access outside business hours → alert
- High-value transaction (>$10K) → review
- Unusual IP location → flag for review

### 11. Regularly Test Security Systems

**Requirement**: Test security systems and processes regularly.

**What we do quarterly**:
- **Penetration testing**: Hired third-party ethical hackers ($8K/test)
- **Vulnerability scanning**: Automated weekly (Nessus)
- **Code review**: All PRs require security review
- **Disaster recovery drill**: Simulate breach, test response

**Example finding** (Q3 2025 pentest):
- Vulnerability: Rate limiting insufficient on password reset
- Risk: Brute force attack possible
- Fix: Implemented exponential backoff + CAPTCHA
- Time to fix: 72 hours

### 12. Maintain Information Security Policy

**Requirement**: Security policy that addresses information security for all personnel.

**What we created**:
- 45-page security policy document
- Annual security training for all employees (mandatory)
- Incident response playbook
- Data breach notification procedure (72-hour disclosure)

**Policy highlights**:
- Password requirements: 16+ chars, special chars, no reuse
- Email phishing simulations: Monthly tests
- Clean desk policy: No printed cardholder data
- Data classification: Public, Internal, Confidential, Restricted

## The Audit Process

**Pre-audit preparation** (Month 5-6):
- Self-assessment questionnaire (SAQ): 300+ questions
- Evidence collection: Screenshots, logs, policies
- Gap remediation: Fix any remaining issues

**Audit week**:
- Day 1: Kickoff, document review
- Day 2-3: Technical testing, interviews
- Day 4: Findings review
- Day 5: Final report

**Our findings**:
- 2 minor issues (fixed same day)
- 0 major issues
- Result: **Certification achieved** ✅

## Ongoing Compliance (Post-Certification)

Certification isn't one-and-done. Ongoing requirements:

**Quarterly**:
- Vulnerability scans (Approved Scanning Vendor)
- Security policy review
- Access control audit

**Annually**:
- Full PCI-DSS re-assessment
- Penetration testing
- Employee security training refresh

**Cost**: $3K/month (scanning + monitoring tools)

## Common Pitfalls & How to Avoid

### Pitfall 1: Treating PCI as Checkbox Exercise
Many companies rush through compliance without understanding WHY.

**Fix**: Security-first mindset. PCI is minimum; go beyond it.

### Pitfall 2: Neglecting Vendor Compliance
If you use third-party services (payment gateway, cloud hosting), they must be PCI compliant too.

**Fix**: Verify vendor certifications (AOC - Attestation of Compliance)

### Pitfall 3: Lack of Documentation
Auditors need proof, not promises.

**Fix**: Document everything: policies, procedures, change logs, training records

### Pitfall 4: Over-Scoping CDE
The more systems in Cardholder Data Environment, the harder (and costlier) compliance becomes.

**Fix**: Minimize CDE. Use tokenization to reduce scope dramatically.

## Total Cost of PCI-DSS Compliance

**One-time**:
- QSA audit: $25K
- Security consulting: $30K
- Implementation (engineering time): $30K
**Total**: $85K

**Recurring**:
- Quarterly scans: $1K
- Security tools: $2K/month
- Annual re-audit: $15K
**Total**: ~$40K/year

**ROI**: Customer trust, legal protection, ability to process payments. Worth every dollar.

## Key Takeaways

1. **Start early**: Don't wait until you need certification. Build security in from day 1.
2. **Use tokenization**: Never store card numbers. Let Stripe/Xendit handle it.
3. **Automate compliance**: Manual processes don't scale. Automate scans, patches, monitoring.
4. **Document religiously**: If it's not documented, it didn't happen (in auditor's eyes).
5. **Continuous improvement**: Compliance is a journey, not a destination.

PCI-DSS is challenging but achievable. With the right approach, tools, and mindset, you can build a secure, compliant payment platform that earns customer trust.
#fintech#compliance#PCI-DSS#security#payment processing#regulations

Share this article