rma-payment-gateway 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +60 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/README.md +446 -0
- data/Rakefile +12 -0
- data/docs/API.md +339 -0
- data/docs/EXAMPLES.md +650 -0
- data/docs/FLOW_DIAGRAM.md +440 -0
- data/docs/QUICK_REFERENCE.md +323 -0
- data/docs/README.md +259 -0
- data/docs/SECURITY.md +506 -0
- data/docs/USAGE_GUIDE.md +522 -0
- data/lib/rma/payment/gateway/account_inquiry.rb +69 -0
- data/lib/rma/payment/gateway/authorization.rb +81 -0
- data/lib/rma/payment/gateway/client.rb +124 -0
- data/lib/rma/payment/gateway/configuration.rb +42 -0
- data/lib/rma/payment/gateway/debit_request.rb +65 -0
- data/lib/rma/payment/gateway/errors.rb +42 -0
- data/lib/rma/payment/gateway/utils.rb +130 -0
- data/lib/rma/payment/gateway/version.rb +9 -0
- data/lib/rma/payment/gateway.rb +24 -0
- data/sig/rma/payment/gateway.rbs +8 -0
- metadata +65 -0
data/docs/SECURITY.md
ADDED
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
# Security Guide
|
|
2
|
+
|
|
3
|
+
This document outlines security best practices for integrating the RMA Payment Gateway into your application.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Overview](#overview)
|
|
8
|
+
- [Configuration Security](#configuration-security)
|
|
9
|
+
- [Data Protection](#data-protection)
|
|
10
|
+
- [Network Security](#network-security)
|
|
11
|
+
- [Application Security](#application-security)
|
|
12
|
+
- [Compliance](#compliance)
|
|
13
|
+
- [Incident Response](#incident-response)
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
Payment processing requires strict security measures to protect sensitive customer data and prevent fraud. This guide covers essential security practices for the RMA Payment Gateway integration.
|
|
18
|
+
|
|
19
|
+
## Configuration Security
|
|
20
|
+
|
|
21
|
+
### 1. RSA Private Key Management
|
|
22
|
+
|
|
23
|
+
**DO:**
|
|
24
|
+
- ✅ Store RSA private keys outside the application directory
|
|
25
|
+
- ✅ Use file permissions to restrict access (chmod 600)
|
|
26
|
+
- ✅ Use environment variables for key paths
|
|
27
|
+
- ✅ Rotate keys periodically
|
|
28
|
+
- ✅ Keep backup keys in secure storage
|
|
29
|
+
|
|
30
|
+
**DON'T:**
|
|
31
|
+
- ❌ Commit private keys to version control
|
|
32
|
+
- ❌ Store keys in the application directory
|
|
33
|
+
- ❌ Share keys via email or chat
|
|
34
|
+
- ❌ Use the same key across environments
|
|
35
|
+
|
|
36
|
+
**Example:**
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Set proper permissions
|
|
40
|
+
chmod 600 /secure/path/rma_private_key.pem
|
|
41
|
+
chown app_user:app_group /secure/path/rma_private_key.pem
|
|
42
|
+
|
|
43
|
+
# Verify permissions
|
|
44
|
+
ls -la /secure/path/rma_private_key.pem
|
|
45
|
+
# Should show: -rw------- 1 app_user app_group
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2. Environment Variables
|
|
49
|
+
|
|
50
|
+
**DO:**
|
|
51
|
+
- ✅ Use `.env` files for local development
|
|
52
|
+
- ✅ Use secure secret management in production (e.g., AWS Secrets Manager, HashiCorp Vault)
|
|
53
|
+
- ✅ Add `.env` to `.gitignore`
|
|
54
|
+
- ✅ Use different credentials for each environment
|
|
55
|
+
|
|
56
|
+
**Example `.gitignore`:**
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
.env
|
|
60
|
+
.env.local
|
|
61
|
+
.env.*.local
|
|
62
|
+
config/rma_private_key.pem
|
|
63
|
+
*.pem
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Example Production Setup (Rails):**
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
# config/initializers/rma_payment_gateway.rb
|
|
70
|
+
Rma::Payment::Gateway.configure do |config|
|
|
71
|
+
# Use Rails credentials or environment variables
|
|
72
|
+
config.base_url = Rails.application.credentials.dig(:rma, :base_url) || ENV['RMA_BASE_URL']
|
|
73
|
+
config.rsa_key_path = Rails.application.credentials.dig(:rma, :key_path) || ENV['RMA_RSA_KEY_PATH']
|
|
74
|
+
config.beneficiary_id = Rails.application.credentials.dig(:rma, :beneficiary_id) || ENV['RMA_BENEFICIARY_ID']
|
|
75
|
+
config.payment_description = ENV['RMA_PAYMENT_DESCRIPTION']
|
|
76
|
+
end
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 3. Configuration Validation
|
|
80
|
+
|
|
81
|
+
Always validate configuration on application startup:
|
|
82
|
+
|
|
83
|
+
```ruby
|
|
84
|
+
# config/initializers/rma_payment_gateway.rb
|
|
85
|
+
config = Rma::Payment::Gateway.configuration
|
|
86
|
+
|
|
87
|
+
unless config.valid?
|
|
88
|
+
raise "RMA Payment Gateway configuration is invalid: #{config.missing_fields.join(', ')}"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Verify RSA key file exists and is readable
|
|
92
|
+
unless File.exist?(config.rsa_key_path)
|
|
93
|
+
raise "RMA RSA key file not found: #{config.rsa_key_path}"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
unless File.readable?(config.rsa_key_path)
|
|
97
|
+
raise "RMA RSA key file is not readable: #{config.rsa_key_path}"
|
|
98
|
+
end
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Data Protection
|
|
102
|
+
|
|
103
|
+
### 1. Sensitive Data Handling
|
|
104
|
+
|
|
105
|
+
**Never log or store:**
|
|
106
|
+
- OTP codes
|
|
107
|
+
- Full account numbers (mask if needed)
|
|
108
|
+
- RSA private keys
|
|
109
|
+
- Customer passwords
|
|
110
|
+
|
|
111
|
+
**Example - Masked Logging:**
|
|
112
|
+
|
|
113
|
+
```ruby
|
|
114
|
+
def log_payment_attempt(transaction_id, account_number)
|
|
115
|
+
Rails.logger.info({
|
|
116
|
+
event: 'payment_attempt',
|
|
117
|
+
transaction_id: transaction_id,
|
|
118
|
+
account_number: Rma::Payment::Gateway::Utils.mask_sensitive(account_number, 2),
|
|
119
|
+
timestamp: Time.current
|
|
120
|
+
}.to_json)
|
|
121
|
+
end
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 2. Database Security
|
|
125
|
+
|
|
126
|
+
**Encrypt sensitive data at rest:**
|
|
127
|
+
|
|
128
|
+
```ruby
|
|
129
|
+
# Using Rails encrypted attributes
|
|
130
|
+
class Payment < ApplicationRecord
|
|
131
|
+
encrypts :customer_account_number
|
|
132
|
+
encrypts :rma_transaction_id
|
|
133
|
+
|
|
134
|
+
# Don't store OTP - it's single-use
|
|
135
|
+
end
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 3. Data Retention
|
|
139
|
+
|
|
140
|
+
**Implement data retention policies:**
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
class Payment < ApplicationRecord
|
|
144
|
+
# Delete old payment records after retention period
|
|
145
|
+
scope :expired, -> { where('created_at < ?', 7.years.ago) }
|
|
146
|
+
|
|
147
|
+
def self.cleanup_old_records
|
|
148
|
+
expired.find_each do |payment|
|
|
149
|
+
payment.anonymize! # Remove PII
|
|
150
|
+
payment.destroy if payment.can_be_deleted?
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 4. PII Protection
|
|
157
|
+
|
|
158
|
+
**Minimize PII collection:**
|
|
159
|
+
|
|
160
|
+
```ruby
|
|
161
|
+
# Only collect what's necessary
|
|
162
|
+
def create_payment(order)
|
|
163
|
+
client.authorization.call(
|
|
164
|
+
order.number,
|
|
165
|
+
order.total,
|
|
166
|
+
order.customer_email # Only email, not full customer details
|
|
167
|
+
)
|
|
168
|
+
end
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Network Security
|
|
172
|
+
|
|
173
|
+
### 1. HTTPS Only
|
|
174
|
+
|
|
175
|
+
**Always use HTTPS:**
|
|
176
|
+
|
|
177
|
+
```ruby
|
|
178
|
+
# Verify base URL uses HTTPS
|
|
179
|
+
config = Rma::Payment::Gateway.configuration
|
|
180
|
+
|
|
181
|
+
unless config.base_url.start_with?('https://')
|
|
182
|
+
raise "RMA base URL must use HTTPS: #{config.base_url}"
|
|
183
|
+
end
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### 2. SSL/TLS Configuration
|
|
187
|
+
|
|
188
|
+
**Use strong SSL/TLS settings:**
|
|
189
|
+
|
|
190
|
+
```ruby
|
|
191
|
+
# In production, verify SSL certificates
|
|
192
|
+
Rma::Payment::Gateway.configure do |config|
|
|
193
|
+
config.base_url = ENV['RMA_BASE_URL']
|
|
194
|
+
# Faraday will verify SSL by default
|
|
195
|
+
end
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 3. Network Timeouts
|
|
199
|
+
|
|
200
|
+
**Set appropriate timeouts to prevent hanging:**
|
|
201
|
+
|
|
202
|
+
```ruby
|
|
203
|
+
Rma::Payment::Gateway.configure do |config|
|
|
204
|
+
config.timeout = 30 # Request timeout
|
|
205
|
+
config.open_timeout = 10 # Connection timeout
|
|
206
|
+
end
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### 4. IP Whitelisting
|
|
210
|
+
|
|
211
|
+
**Restrict API access by IP (if supported):**
|
|
212
|
+
|
|
213
|
+
```ruby
|
|
214
|
+
# Configure firewall rules to only allow outbound connections
|
|
215
|
+
# to RMA Payment Gateway IP addresses
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Application Security
|
|
219
|
+
|
|
220
|
+
### 1. Input Validation
|
|
221
|
+
|
|
222
|
+
**Always validate user inputs:**
|
|
223
|
+
|
|
224
|
+
```ruby
|
|
225
|
+
class PaymentController < ApplicationController
|
|
226
|
+
def create
|
|
227
|
+
# Validate before processing
|
|
228
|
+
validate_payment_params!
|
|
229
|
+
|
|
230
|
+
# Process payment
|
|
231
|
+
process_payment
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
private
|
|
235
|
+
|
|
236
|
+
def validate_payment_params!
|
|
237
|
+
unless Rma::Payment::Gateway::Utils.valid_amount?(params[:amount])
|
|
238
|
+
raise ActionController::BadRequest, "Invalid amount"
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
unless Rma::Payment::Gateway::Utils.valid_email?(params[:email])
|
|
242
|
+
raise ActionController::BadRequest, "Invalid email"
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
unless Rma::Payment::Gateway::Utils.valid_bank_code?(params[:bank_id])
|
|
246
|
+
raise ActionController::BadRequest, "Invalid bank code"
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### 2. CSRF Protection
|
|
253
|
+
|
|
254
|
+
**Enable CSRF protection:**
|
|
255
|
+
|
|
256
|
+
```ruby
|
|
257
|
+
# Rails - enabled by default
|
|
258
|
+
class ApplicationController < ActionController::Base
|
|
259
|
+
protect_from_forgery with: :exception
|
|
260
|
+
end
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### 3. Rate Limiting
|
|
264
|
+
|
|
265
|
+
**Implement rate limiting:**
|
|
266
|
+
|
|
267
|
+
```ruby
|
|
268
|
+
# Using Rack::Attack
|
|
269
|
+
class Rack::Attack
|
|
270
|
+
# Limit payment attempts per IP
|
|
271
|
+
throttle('payments/ip', limit: 5, period: 1.hour) do |req|
|
|
272
|
+
req.ip if req.path.start_with?('/payments') && req.post?
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# Limit payment attempts per user
|
|
276
|
+
throttle('payments/user', limit: 10, period: 1.hour) do |req|
|
|
277
|
+
req.session[:user_id] if req.path.start_with?('/payments') && req.post?
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### 4. Session Security
|
|
283
|
+
|
|
284
|
+
**Secure session management:**
|
|
285
|
+
|
|
286
|
+
```ruby
|
|
287
|
+
# Rails session configuration
|
|
288
|
+
Rails.application.config.session_store :cookie_store,
|
|
289
|
+
key: '_app_session',
|
|
290
|
+
secure: Rails.env.production?, # HTTPS only in production
|
|
291
|
+
httponly: true, # Not accessible via JavaScript
|
|
292
|
+
same_site: :lax # CSRF protection
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### 5. Authorization
|
|
296
|
+
|
|
297
|
+
**Verify user authorization:**
|
|
298
|
+
|
|
299
|
+
```ruby
|
|
300
|
+
class PaymentsController < ApplicationController
|
|
301
|
+
before_action :authenticate_user!
|
|
302
|
+
before_action :authorize_payment!
|
|
303
|
+
|
|
304
|
+
def complete
|
|
305
|
+
# User can only complete their own payments
|
|
306
|
+
@payment = current_user.payments.find(params[:id])
|
|
307
|
+
# Process payment
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
private
|
|
311
|
+
|
|
312
|
+
def authorize_payment!
|
|
313
|
+
unless current_user.can_make_payment?
|
|
314
|
+
redirect_to root_path, alert: 'Not authorized'
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### 6. Idempotency
|
|
321
|
+
|
|
322
|
+
**Prevent duplicate payments:**
|
|
323
|
+
|
|
324
|
+
```ruby
|
|
325
|
+
class Payment < ApplicationRecord
|
|
326
|
+
validates :order_number, uniqueness: { scope: :status }
|
|
327
|
+
|
|
328
|
+
def self.create_or_find_by_order(order_number)
|
|
329
|
+
# Atomic operation to prevent race conditions
|
|
330
|
+
transaction do
|
|
331
|
+
find_or_create_by!(order_number: order_number) do |payment|
|
|
332
|
+
payment.status = 'pending'
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## Compliance
|
|
340
|
+
|
|
341
|
+
### 1. PCI DSS Compliance
|
|
342
|
+
|
|
343
|
+
**Key requirements:**
|
|
344
|
+
- Don't store card data (RMA handles this)
|
|
345
|
+
- Use HTTPS for all communications
|
|
346
|
+
- Implement access controls
|
|
347
|
+
- Maintain audit logs
|
|
348
|
+
- Regular security testing
|
|
349
|
+
|
|
350
|
+
### 2. Data Privacy Regulations
|
|
351
|
+
|
|
352
|
+
**GDPR/Privacy compliance:**
|
|
353
|
+
|
|
354
|
+
```ruby
|
|
355
|
+
class Customer < ApplicationRecord
|
|
356
|
+
# Right to be forgotten
|
|
357
|
+
def anonymize!
|
|
358
|
+
update!(
|
|
359
|
+
email: "deleted_#{id}@example.com",
|
|
360
|
+
name: "Deleted User",
|
|
361
|
+
phone: nil
|
|
362
|
+
)
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
# Data export
|
|
366
|
+
def export_data
|
|
367
|
+
{
|
|
368
|
+
personal_info: attributes.slice('name', 'email', 'phone'),
|
|
369
|
+
payments: payments.map(&:export_data)
|
|
370
|
+
}
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### 3. Audit Logging
|
|
376
|
+
|
|
377
|
+
**Maintain comprehensive audit logs:**
|
|
378
|
+
|
|
379
|
+
```ruby
|
|
380
|
+
class AuditLog < ApplicationRecord
|
|
381
|
+
def self.log_payment_event(event_type, user, details)
|
|
382
|
+
create!(
|
|
383
|
+
event_type: event_type,
|
|
384
|
+
user_id: user&.id,
|
|
385
|
+
ip_address: details[:ip],
|
|
386
|
+
user_agent: details[:user_agent],
|
|
387
|
+
details: details.to_json,
|
|
388
|
+
created_at: Time.current
|
|
389
|
+
)
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
# Usage
|
|
394
|
+
AuditLog.log_payment_event('payment_authorized', current_user, {
|
|
395
|
+
transaction_id: response["bfs_bfsTxnId"],
|
|
396
|
+
amount: amount,
|
|
397
|
+
ip: request.remote_ip,
|
|
398
|
+
user_agent: request.user_agent
|
|
399
|
+
})
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
## Incident Response
|
|
403
|
+
|
|
404
|
+
### 1. Security Monitoring
|
|
405
|
+
|
|
406
|
+
**Monitor for suspicious activity:**
|
|
407
|
+
|
|
408
|
+
```ruby
|
|
409
|
+
class SecurityMonitor
|
|
410
|
+
def self.check_suspicious_payment(payment)
|
|
411
|
+
alerts = []
|
|
412
|
+
|
|
413
|
+
# Multiple failed attempts
|
|
414
|
+
if payment.user.failed_payments.last_hour.count > 5
|
|
415
|
+
alerts << "Multiple failed payments"
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
# Unusual amount
|
|
419
|
+
if payment.amount > payment.user.average_payment_amount * 10
|
|
420
|
+
alerts << "Unusually large payment"
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
# Different location
|
|
424
|
+
if payment.ip_country != payment.user.usual_country
|
|
425
|
+
alerts << "Payment from unusual location"
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
notify_security_team(alerts) if alerts.any?
|
|
429
|
+
end
|
|
430
|
+
end
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### 2. Incident Response Plan
|
|
434
|
+
|
|
435
|
+
**Steps to take if security incident occurs:**
|
|
436
|
+
|
|
437
|
+
1. **Immediate Actions:**
|
|
438
|
+
- Disable affected accounts
|
|
439
|
+
- Revoke compromised credentials
|
|
440
|
+
- Block suspicious IP addresses
|
|
441
|
+
|
|
442
|
+
2. **Investigation:**
|
|
443
|
+
- Review audit logs
|
|
444
|
+
- Identify scope of breach
|
|
445
|
+
- Document findings
|
|
446
|
+
|
|
447
|
+
3. **Remediation:**
|
|
448
|
+
- Patch vulnerabilities
|
|
449
|
+
- Reset credentials
|
|
450
|
+
- Notify affected users
|
|
451
|
+
|
|
452
|
+
4. **Prevention:**
|
|
453
|
+
- Update security measures
|
|
454
|
+
- Conduct security training
|
|
455
|
+
- Review and update policies
|
|
456
|
+
|
|
457
|
+
### 3. Emergency Contacts
|
|
458
|
+
|
|
459
|
+
**Maintain emergency contact list:**
|
|
460
|
+
|
|
461
|
+
```ruby
|
|
462
|
+
# config/security_contacts.yml
|
|
463
|
+
security_team:
|
|
464
|
+
primary: security@example.com
|
|
465
|
+
phone: +975-XXXXXXXX
|
|
466
|
+
|
|
467
|
+
rma_support:
|
|
468
|
+
email: support@rma.org.bt
|
|
469
|
+
phone: +975-XXXXXXXX
|
|
470
|
+
|
|
471
|
+
incident_response:
|
|
472
|
+
email: incidents@example.com
|
|
473
|
+
escalation: cto@example.com
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
## Security Checklist
|
|
477
|
+
|
|
478
|
+
Before going to production:
|
|
479
|
+
|
|
480
|
+
- [ ] RSA private keys stored securely
|
|
481
|
+
- [ ] Environment variables configured
|
|
482
|
+
- [ ] HTTPS enforced
|
|
483
|
+
- [ ] Input validation implemented
|
|
484
|
+
- [ ] CSRF protection enabled
|
|
485
|
+
- [ ] Rate limiting configured
|
|
486
|
+
- [ ] Session security configured
|
|
487
|
+
- [ ] Audit logging implemented
|
|
488
|
+
- [ ] Error handling doesn't leak sensitive info
|
|
489
|
+
- [ ] Security monitoring in place
|
|
490
|
+
- [ ] Incident response plan documented
|
|
491
|
+
- [ ] Team trained on security practices
|
|
492
|
+
- [ ] Regular security audits scheduled
|
|
493
|
+
- [ ] Backup and recovery procedures tested
|
|
494
|
+
|
|
495
|
+
## Resources
|
|
496
|
+
|
|
497
|
+
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
|
498
|
+
- [PCI DSS Requirements](https://www.pcisecuritystandards.org/)
|
|
499
|
+
- [Rails Security Guide](https://guides.rubyonrails.org/security.html)
|
|
500
|
+
|
|
501
|
+
## Support
|
|
502
|
+
|
|
503
|
+
For security concerns:
|
|
504
|
+
- Email: tashii.dendupp@gmail.com
|
|
505
|
+
- GitHub Security Advisories: https://github.com/dcplbt/rma-payment-gateway/security
|
|
506
|
+
|