Security & Compliance
Protect your business and customers with comprehensive security measures and ensure compliance with regulatory requirements.
🛡️ Security Overview
Security Principles
Torque follows industry-leading security practices to protect your business:
Data Protection
- End-to-End Encryption: All data encrypted in transit and at rest
- Secure Storage: Data stored in enterprise-grade secure facilities
- Access Controls: Strict access controls and authentication
- Regular Audits: Continuous security monitoring and testing
Infrastructure Security
- Cloud Security: Built on secure cloud infrastructure
- Network Security: Protected network with firewalls and monitoring
- Physical Security: Secure data centers with 24/7 monitoring
- Disaster Recovery: Comprehensive backup and recovery systems
🔑 API Security
API Key Management
Key Security Best Practices
Generate Strong Keys
# Use our secure key generation
# Keys are automatically generated with high entropy
# Format: torque_live_64characterstring
Secure Storage
# Environment Variables (Recommended)
export TORQUE_API_KEY="torque_live_your_api_key_here"
export TORQUE_BUSINESS_ID="business_your_business_id"
# Never commit to version control
# .gitignore should include:
.env
*.env
config/secrets.*
Key Rotation
- Regular Rotation: Rotate keys every 90 days
- Immediate Rotation: Rotate immediately if compromised
- Gradual Rollout: Update applications gradually
- Monitor Usage: Watch for unusual API activity
Key Permissions
Permission Levels
- Read Only: View orders, analytics, customer data
- Write Access: Create checkout links, manage orders
- Admin Access: Full account management (use sparingly)
Access Control
// Example: Role-based API access
const apiPermissions = {
'analytics': ['read'],
'orders': ['read', 'write'],
'webhooks': ['read', 'write'],
'business': ['read', 'write', 'admin']
};
function checkPermission(resource, action) {
const permissions = apiPermissions[resource] || [];
return permissions.includes(action);
}
Request Security
HTTPS Enforcement
- Always Use HTTPS: All API requests must use HTTPS
- Certificate Validation: Verify SSL certificates
- TLS 1.2+: Use modern TLS versions only
Request Validation
// Validate all input data
function validateCheckoutRequest(data) {
const errors = [];
// Required fields
if (!data.businessId) errors.push('Business ID is required');
if (!data.cart?.items?.length) errors.push('Cart must contain items');
if (!data.customerData?.email) errors.push('Customer email is required');
// Data format validation
if (data.cart?.items) {
data.cart.items.forEach((item, index) => {
if (!item.productId) errors.push(`Item ${index}: Product ID required`);
if (!item.quantity || item.quantity < 1) errors.push(`Item ${index}: Valid quantity required`);
if (!item.price || item.price <= 0) errors.push(`Item ${index}: Valid price required`);
});
}
return errors;
}
Rate Limiting
// Implement rate limiting
class RateLimiter {
constructor(maxRequests = 1000, windowMs = 60000) {
this.maxRequests = maxRequests;
this.windowMs = windowMs;
this.requests = new Map();
}
isAllowed(clientId) {
const now = Date.now();
const clientRequests = this.requests.get(clientId) || [];
// Remove old requests
const recentRequests = clientRequests.filter(time => now - time < this.windowMs);
if (recentRequests.length >= this.maxRequests) {
return false;
}
// Add current request
recentRequests.push(now);
this.requests.set(clientId, recentRequests);
return true;
}
}
🔗 Webhook Security
Webhook Verification
Signature Verification
HMAC SHA256 Verification
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// Usage in webhook handler
app.post('/webhooks/torque', (req, res) => {
const signature = req.headers['x-torque-signature'];
const payload = req.body;
if (!verifyWebhookSignature(payload, signature, webhookSecret)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process webhook...
});
PHP Verification
<?php
function verifyWebhookSignature($payload, $signature, $secret) {
$expectedSignature = hash_hmac('sha256', $payload, $secret);
return hash_equals($expectedSignature, $signature);
}
// Usage
$signature = $_SERVER['HTTP_X_TORQUE_SIGNATURE'] ?? '';
$payload = file_get_contents('php://input');
if (!verifyWebhookSignature($payload, $signature, $webhookSecret)) {
http_response_code(401);
echo json_encode(['error' => 'Invalid signature']);
exit;
}
?>
Python Verification
import hmac
import hashlib
def verify_webhook_signature(payload, signature, secret):
expected_signature = hmac.new(
secret.encode('utf-8'),
payload.encode('utf-8'),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected_signature, signature)
# Usage
@app.route('/webhooks/torque', methods=['POST'])
def webhook():
signature = request.headers.get('X-Torque-Signature', '')
payload = request.get_data(as_text=True)
if not verify_webhook_signature(payload, signature, webhook_secret):
return jsonify({'error': 'Invalid signature'}), 401
# Process webhook...
Webhook Security Best Practices
Endpoint Security
- HTTPS Only: Require HTTPS for all webhook endpoints
- Authentication: Implement additional authentication if needed
- IP Whitelisting: Restrict webhook sources if possible
- Request Validation: Validate all webhook data
Error Handling
// Secure error handling
app.post('/webhooks/torque', async (req, res) => {
try {
// Verify signature first
const signature = req.headers['x-torque-signature'];
if (!verifyWebhookSignature(req.body, signature, webhookSecret)) {
return res.status(401).json({ error: 'Unauthorized' });
}
// Process webhook
await processWebhook(req.body);
// Return success
res.json({ success: true });
} catch (error) {
// Log error securely (don't expose sensitive data)
console.error('Webhook processing error:', {
timestamp: new Date().toISOString(),
error: error.message,
stack: error.stack
});
// Return generic error
res.status(500).json({ error: 'Internal server error' });
}
});
🔒 Data Security
Customer Data Protection
PII Handling
- Data Minimization: Only collect necessary data
- Encryption: Encrypt sensitive data at rest
- Access Control: Limit access to customer data
- Data Retention: Implement data retention policies
Secure Data Storage
// Example: Secure customer data handling
class CustomerDataManager {
constructor(encryptionKey) {
this.encryptionKey = encryptionKey;
}
encryptCustomerData(data) {
// Encrypt sensitive fields
const sensitiveFields = ['email', 'phone', 'address'];
const encrypted = { ...data };
sensitiveFields.forEach(field => {
if (data[field]) {
encrypted[field] = this.encrypt(data[field]);
}
});
return encrypted;
}
decryptCustomerData(encryptedData) {
// Decrypt sensitive fields
const sensitiveFields = ['email', 'phone', 'address'];
const decrypted = { ...encryptedData };
sensitiveFields.forEach(field => {
if (encryptedData[field]) {
decrypted[field] = this.decrypt(encryptedData[field]);
}
});
return decrypted;
}
}
Payment Data Security
PCI Compliance
- No Payment Storage: Never store payment card data
- Tokenization: Use payment tokens when possible
- Secure Transmission: Encrypt all payment data in transit
- Access Logging: Log all access to payment information
Secure Payment Handling
// Example: Secure payment processing
class PaymentProcessor {
constructor() {
this.paymentGateway = new SecurePaymentGateway();
}
async processPayment(paymentData) {
try {
// Validate payment data
this.validatePaymentData(paymentData);
// Process payment securely
const result = await this.paymentGateway.process(paymentData);
// Log payment attempt (no sensitive data)
this.logPaymentAttempt({
amount: paymentData.amount,
currency: paymentData.currency,
status: result.status,
timestamp: new Date().toISOString()
});
return result;
} catch (error) {
// Log error securely
this.logPaymentError(error);
throw error;
}
}
validatePaymentData(data) {
// Validate payment data without exposing sensitive information
if (!data.amount || data.amount <= 0) {
throw new Error('Invalid payment amount');
}
if (!data.currency) {
throw new Error('Payment currency required');
}
}
}
📋 Compliance Requirements
GDPR Compliance
Data Protection Principles
- Lawful Processing: Process data only with legal basis
- Purpose Limitation: Use data only for specified purposes
- Data Minimization: Collect only necessary data
- Accuracy: Keep data accurate and up-to-date
- Storage Limitation: Don't keep data longer than needed
- Integrity & Confidentiality: Protect data security
Customer Rights
- Right to Access: Provide data access upon request
- Right to Rectification: Allow data correction
- Right to Erasure: Delete data upon request
- Right to Portability: Export data in standard format
- Right to Object: Allow processing objections
- Right to Restriction: Limit data processing
Implementation
// Example: GDPR compliance implementation
class GDPRCompliance {
constructor() {
this.dataRetentionDays = 365; // 1 year retention
}
async handleDataRequest(customerId, requestType) {
switch (requestType) {
case 'access':
return await this.provideDataAccess(customerId);
case 'rectification':
return await this.rectifyData(customerId);
case 'erasure':
return await this.eraseData(customerId);
case 'portability':
return await this.exportData(customerId);
default:
throw new Error('Invalid request type');
}
}
async provideDataAccess(customerId) {
const customerData = await this.getCustomerData(customerId);
return {
personalData: customerData.personal,
processingPurposes: ['order_processing', 'customer_support'],
dataRetention: this.dataRetentionDays,
rights: ['access', 'rectification', 'erasure', 'portability']
};
}
async eraseData(customerId) {
// Implement data erasure
await this.anonymizeCustomerData(customerId);
await this.logDataErasure(customerId);
return { success: true, message: 'Data erased successfully' };
}
}
CCPA Compliance
California Privacy Rights
- Right to Know: What personal information is collected
- Right to Delete: Request data deletion
- Right to Opt-Out: Opt out of data sales
- Non-Discrimination: Equal service regardless of privacy choices
Implementation
// Example: CCPA compliance
class CCPACompliance {
constructor() {
this.privacyNotice = this.getPrivacyNotice();
}
async handleCCPARequest(customerId, requestType) {
switch (requestType) {
case 'know':
return await this.provideDataInventory(customerId);
case 'delete':
return await this.deleteCustomerData(customerId);
case 'opt-out':
return await this.optOutOfDataSales(customerId);
default:
throw new Error('Invalid CCPA request type');
}
}
async provideDataInventory(customerId) {
const dataInventory = await this.getDataInventory(customerId);
return {
categories: dataInventory.categories,
sources: dataInventory.sources,
purposes: dataInventory.purposes,
thirdParties: dataInventory.thirdParties
};
}
getPrivacyNotice() {
return {
dataCollection: ['identifiers', 'commercial', 'internet'],
dataUse: ['order_processing', 'customer_support', 'analytics'],
dataSharing: ['payment_processors', 'shipping_partners'],
optOutRights: ['data_sales', 'marketing_communications']
};
}
}
🚨 Security Incident Response
Incident Detection
Monitoring & Alerting
// Example: Security monitoring
class SecurityMonitor {
constructor() {
this.alerts = [];
this.thresholds = {
failedLogins: 5,
apiErrors: 100,
suspiciousActivity: 10
};
}
monitorLoginAttempts(userId, success) {
if (!success) {
this.recordFailedLogin(userId);
this.checkFailedLoginThreshold(userId);
}
}
monitorAPIUsage(clientId, endpoint, responseCode) {
if (responseCode >= 400) {
this.recordAPIError(clientId, endpoint, responseCode);
this.checkAPIErrorThreshold(clientId);
}
}
checkFailedLoginThreshold(userId) {
const failedAttempts = this.getFailedLoginCount(userId);
if (failedAttempts >= this.thresholds.failedLogins) {
this.triggerSecurityAlert('Multiple failed login attempts', { userId, attempts: failedAttempts });
this.lockAccount(userId);
}
}
triggerSecurityAlert(type, details) {
const alert = {
type,
details,
timestamp: new Date().toISOString(),
severity: this.calculateSeverity(type, details)
};
this.alerts.push(alert);
this.notifySecurityTeam(alert);
}
}
Incident Response Plan
Response Steps
- Detection: Identify security incident
- Assessment: Evaluate incident severity
- Containment: Limit incident impact
- Investigation: Determine root cause
- Remediation: Fix security vulnerabilities
- Recovery: Restore normal operations
- Lessons Learned: Improve security measures
Response Team
// Example: Incident response team structure
const incidentResponseTeam = {
incidentCommander: {
name: 'Security Manager',
responsibilities: ['Overall incident management', 'Communication coordination']
},
technicalLead: {
name: 'Senior Developer',
responsibilities: ['Technical investigation', 'Vulnerability assessment']
},
communicationsLead: {
name: 'PR Manager',
responsibilities: ['Customer communication', 'External reporting']
},
legalAdvisor: {
name: 'Legal Counsel',
responsibilities: ['Compliance requirements', 'Legal obligations']
}
};
🔐 Security Best Practices
Development Security
Code Security
- Input Validation: Validate all user inputs
- Output Encoding: Encode output to prevent XSS
- SQL Injection Prevention: Use parameterized queries
- Authentication: Implement strong authentication
- Authorization: Enforce proper access controls
Security Testing
// Example: Security testing framework
class SecurityTester {
constructor() {
this.testResults = [];
}
async runSecurityTests() {
await this.testAuthentication();
await this.testAuthorization();
await this.testInputValidation();
await this.testOutputEncoding();
await this.testSQLInjection();
await this.testXSS();
return this.generateSecurityReport();
}
async testAuthentication() {
// Test authentication bypass attempts
const testCases = [
{ username: '', password: 'test' },
{ username: 'admin', password: '' },
{ username: 'admin', password: 'admin' },
{ username: 'admin', password: 'password' }
];
for (const testCase of testCases) {
const result = await this.testLogin(testCase);
this.testResults.push({
test: 'Authentication',
case: testCase,
result: result.success ? 'FAIL' : 'PASS',
details: result.message
});
}
}
generateSecurityReport() {
const passed = this.testResults.filter(r => r.result === 'PASS').length;
const total = this.testResults.length;
const score = (passed / total) * 100;
return {
score,
passed,
total,
results: this.testResults,
recommendations: this.generateRecommendations()
};
}
}
Operational Security
Access Management
- Principle of Least Privilege: Grant minimal necessary access
- Role-Based Access Control: Assign permissions by role
- Regular Access Reviews: Review access permissions regularly
- Access Logging: Log all access attempts and actions
Security Monitoring
// Example: Security monitoring dashboard
class SecurityDashboard {
constructor() {
this.metrics = {
failedLogins: 0,
suspiciousActivities: 0,
securityAlerts: 0,
complianceScore: 100
};
}
updateMetrics(event) {
switch (event.type) {
case 'failed_login':
this.metrics.failedLogins++;
break;
case 'suspicious_activity':
this.metrics.suspiciousActivities++;
break;
case 'security_alert':
this.metrics.securityAlerts++;
break;
}
this.updateDashboard();
}
updateDashboard() {
// Update real-time dashboard
this.displayMetrics(this.metrics);
this.checkThresholds(this.metrics);
}
checkThresholds(metrics) {
if (metrics.failedLogins > 10) {
this.triggerHighAlert('High number of failed login attempts');
}
if (metrics.suspiciousActivities > 5) {
this.triggerHighAlert('Multiple suspicious activities detected');
}
}
}
🔗 Next Steps
- Business Onboarding: Complete setup guide
- API Reference: Technical integration
- Business Dashboard: Dashboard management
- Support Resources: Get help and support
Need help with security? Contact our security team at security@torque.fi or check our security documentation.