opaque_id 1.2.0 → 1.4.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.
data/docs/security.md ADDED
@@ -0,0 +1,601 @@
1
+ ---
2
+ layout: default
3
+ title: Security
4
+ nav_order: 9
5
+ description: "Security considerations, best practices, and threat model analysis"
6
+ permalink: /security/
7
+ ---
8
+
9
+ # Security
10
+
11
+ OpaqueId is designed with security as a primary concern, providing cryptographically secure ID generation with protection against various attack vectors. This guide covers security considerations, best practices, and threat model analysis.
12
+
13
+ - TOC
14
+ {:toc}
15
+
16
+ ## Cryptographic Security
17
+
18
+ ### SecureRandom Foundation
19
+
20
+ OpaqueId is built on Ruby's `SecureRandom`, which provides cryptographically secure pseudo-random number generation.
21
+
22
+ ```ruby
23
+ # OpaqueId uses SecureRandom for all random generation
24
+ def generate_secure_id
25
+ # Cryptographically secure random bytes
26
+ byte = SecureRandom.random_bytes(1).unpack1("C")
27
+
28
+ # No predictable patterns
29
+ # No timing attacks
30
+ # No statistical bias
31
+ end
32
+ ```
33
+
34
+ **Security Properties:**
35
+
36
+ - **Cryptographically Secure**: Uses OS entropy sources
37
+ - **Unpredictable**: Cannot be predicted from previous outputs
38
+ - **High Entropy**: Sufficient randomness for security applications
39
+ - **No Patterns**: Prevents statistical analysis attacks
40
+
41
+ ### Entropy Analysis
42
+
43
+ The security of opaque IDs depends on their entropy, which is calculated as:
44
+
45
+ ```
46
+ Entropy = length × log₂(alphabet_size)
47
+ ```
48
+
49
+ #### Entropy Examples
50
+
51
+ | ID Length | Alphabet | Entropy (bits) | Security Level |
52
+ | --------- | ----------------- | -------------- | -------------- |
53
+ | 21 | Alphanumeric (62) | 125.0 | Very High |
54
+ | 21 | Standard (64) | 126.0 | Very High |
55
+ | 15 | Hexadecimal (16) | 60.0 | High |
56
+ | 12 | Numeric (10) | 39.9 | Medium |
57
+ | 8 | Alphanumeric (62) | 47.7 | Medium |
58
+
59
+ #### Security Recommendations
60
+
61
+ ```ruby
62
+ # High security applications (125+ bits entropy)
63
+ class ApiKey < ApplicationRecord
64
+ include OpaqueId::Model
65
+
66
+ self.opaque_id_length = 21
67
+ self.opaque_id_alphabet = OpaqueId::ALPHANUMERIC_ALPHABET
68
+ # Entropy: 125 bits
69
+ end
70
+
71
+ # Medium security applications (60+ bits entropy)
72
+ class User < ApplicationRecord
73
+ include OpaqueId::Model
74
+
75
+ self.opaque_id_length = 15
76
+ self.opaque_id_alphabet = OpaqueId::STANDARD_ALPHABET
77
+ # Entropy: 90 bits
78
+ end
79
+
80
+ # Low security applications (40+ bits entropy)
81
+ class ShortUrl < ApplicationRecord
82
+ include OpaqueId::Model
83
+
84
+ self.opaque_id_length = 8
85
+ self.opaque_id_alphabet = OpaqueId::ALPHANUMERIC_ALPHABET
86
+ # Entropy: 48 bits
87
+ end
88
+ ```
89
+
90
+ ## Security Best Practices
91
+
92
+ ### DO: Recommended Practices
93
+
94
+ #### 1. Use Appropriate ID Length
95
+
96
+ ```ruby
97
+ # High security: 21+ characters
98
+ self.opaque_id_length = 21
99
+
100
+ # Medium security: 15+ characters
101
+ self.opaque_id_length = 15
102
+
103
+ # Low security: 8+ characters
104
+ self.opaque_id_length = 8
105
+ ```
106
+
107
+ #### 2. Choose Secure Alphabets
108
+
109
+ ```ruby
110
+ # High entropy alphabets
111
+ self.opaque_id_alphabet = OpaqueId::ALPHANUMERIC_ALPHABET # 62 characters
112
+ self.opaque_id_alphabet = OpaqueId::STANDARD_ALPHABET # 64 characters
113
+
114
+ # Avoid low entropy alphabets for security-critical applications
115
+ # self.opaque_id_alphabet = "0123456789" # Only 10 characters
116
+ ```
117
+
118
+ #### 3. Implement Proper Access Controls
119
+
120
+ ```ruby
121
+ # Secure API endpoints
122
+ class UsersController < ApplicationController
123
+ before_action :authenticate_user!
124
+ before_action :authorize_user_access!
125
+
126
+ def show
127
+ @user = User.find_by_opaque_id!(params[:id])
128
+ # Additional authorization checks
129
+ end
130
+ end
131
+ ```
132
+
133
+ #### 4. Use HTTPS in Production
134
+
135
+ ```ruby
136
+ # Ensure opaque IDs are transmitted securely
137
+ # Use HTTPS for all API endpoints
138
+ # Implement proper CORS policies
139
+ # Use secure cookies for session management
140
+ ```
141
+
142
+ #### 5. Implement Rate Limiting
143
+
144
+ ```ruby
145
+ # Protect against brute force attacks
146
+ class ApiController < ApplicationController
147
+ before_action :rate_limit_requests
148
+
149
+ private
150
+
151
+ def rate_limit_requests
152
+ # Implement rate limiting
153
+ # Use Redis or similar for distributed rate limiting
154
+ # Log suspicious activity
155
+ end
156
+ end
157
+ ```
158
+
159
+ ### DON'T: Security Anti-Patterns
160
+
161
+ #### 1. Don't Use Predictable Patterns
162
+
163
+ ```ruby
164
+ # BAD: Sequential or predictable IDs
165
+ self.opaque_id_alphabet = "0123456789"
166
+ self.opaque_id_length = 6
167
+ # Generates: 000001, 000002, 000003, etc.
168
+
169
+ # GOOD: Random, unpredictable IDs
170
+ self.opaque_id_alphabet = OpaqueId::ALPHANUMERIC_ALPHABET
171
+ self.opaque_id_length = 21
172
+ # Generates: V1StGXR8_Z5jdHi6B-myT, K8jH2mN9_pL3qR7sT1v, etc.
173
+ ```
174
+
175
+ #### 2. Don't Expose Internal Information
176
+
177
+ ```ruby
178
+ # BAD: Using database IDs in URLs
179
+ def user_path(user)
180
+ "/users/#{user.id}" # Exposes internal ID
181
+ end
182
+
183
+ # GOOD: Using opaque IDs in URLs
184
+ def user_path(user)
185
+ "/users/#{user.opaque_id}" # No internal information exposed
186
+ end
187
+ ```
188
+
189
+ #### 3. Don't Use Weak Entropy
190
+
191
+ ```ruby
192
+ # BAD: Low entropy for security-critical applications
193
+ class ApiKey < ApplicationRecord
194
+ include OpaqueId::Model
195
+
196
+ self.opaque_id_length = 8
197
+ self.opaque_id_alphabet = "0123456789"
198
+ # Only 26.6 bits of entropy
199
+ end
200
+
201
+ # GOOD: High entropy for security-critical applications
202
+ class ApiKey < ApplicationRecord
203
+ include OpaqueId::Model
204
+
205
+ self.opaque_id_length = 32
206
+ self.opaque_id_alphabet = OpaqueId::ALPHANUMERIC_ALPHABET
207
+ # 190.7 bits of entropy
208
+ end
209
+ ```
210
+
211
+ #### 4. Don't Log Sensitive IDs
212
+
213
+ ```ruby
214
+ # BAD: Logging opaque IDs
215
+ Rails.logger.info "User #{user.opaque_id} logged in"
216
+
217
+ # GOOD: Logging without sensitive information
218
+ Rails.logger.info "User #{user.id} logged in"
219
+ ```
220
+
221
+ ## Security Recommendations
222
+
223
+ ### ID Length Recommendations
224
+
225
+ #### High Security (125+ bits entropy)
226
+
227
+ ```ruby
228
+ # API keys, authentication tokens, sensitive data
229
+ self.opaque_id_length = 21
230
+ self.opaque_id_alphabet = OpaqueId::ALPHANUMERIC_ALPHABET
231
+ # Entropy: 125 bits
232
+ # Collision probability: 2.3×10⁻¹⁵ (1M IDs)
233
+ ```
234
+
235
+ #### Medium Security (60+ bits entropy)
236
+
237
+ ```ruby
238
+ # User IDs, order numbers, general identifiers
239
+ self.opaque_id_length = 15
240
+ self.opaque_id_alphabet = OpaqueId::STANDARD_ALPHABET
241
+ # Entropy: 90 bits
242
+ # Collision probability: 2.3×10⁻⁶ (1M IDs)
243
+ ```
244
+
245
+ #### Low Security (40+ bits entropy)
246
+
247
+ ```ruby
248
+ # Short URLs, public identifiers, non-sensitive data
249
+ self.opaque_id_length = 8
250
+ self.opaque_id_alphabet = OpaqueId::ALPHANUMERIC_ALPHABET
251
+ # Entropy: 48 bits
252
+ # Collision probability: 2.3×10⁻² (1M IDs)
253
+ ```
254
+
255
+ ### Alphabet Selection
256
+
257
+ #### High Security Alphabets
258
+
259
+ ```ruby
260
+ # Maximum entropy
261
+ self.opaque_id_alphabet = OpaqueId::STANDARD_ALPHABET
262
+ # 64 characters: A-Z, a-z, 0-9, -, _
263
+
264
+ # High entropy, URL-safe
265
+ self.opaque_id_alphabet = OpaqueId::ALPHANUMERIC_ALPHABET
266
+ # 62 characters: A-Z, a-z, 0-9
267
+ ```
268
+
269
+ #### Medium Security Alphabets
270
+
271
+ ```ruby
272
+ # Hexadecimal
273
+ self.opaque_id_alphabet = "0123456789abcdef"
274
+ # 16 characters: 0-9, a-f
275
+
276
+ # Uppercase alphanumeric
277
+ self.opaque_id_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
278
+ # 36 characters: A-Z, 0-9
279
+ ```
280
+
281
+ #### Low Security Alphabets
282
+
283
+ ```ruby
284
+ # Numeric only
285
+ self.opaque_id_alphabet = "0123456789"
286
+ # 10 characters: 0-9
287
+
288
+ # Binary
289
+ self.opaque_id_alphabet = "01"
290
+ # 2 characters: 0, 1
291
+ ```
292
+
293
+ ## Threat Model Considerations
294
+
295
+ ### Attack Vectors
296
+
297
+ #### 1. Brute Force Attacks
298
+
299
+ **Threat**: Attackers attempt to guess valid opaque IDs
300
+
301
+ **Mitigation**:
302
+
303
+ ```ruby
304
+ # Use sufficient entropy
305
+ self.opaque_id_length = 21
306
+ self.opaque_id_alphabet = OpaqueId::ALPHANUMERIC_ALPHABET
307
+
308
+ # Implement rate limiting
309
+ # Monitor for suspicious activity
310
+ # Use proper authentication
311
+ ```
312
+
313
+ **Analysis**:
314
+
315
+ - 21-character alphanumeric ID: 62²¹ ≈ 2.3×10³⁷ possible values
316
+ - Time to brute force: Extremely long (exponential with ID length and alphabet size)
317
+
318
+ #### 2. Timing Attacks
319
+
320
+ **Threat**: Attackers use timing information to predict IDs
321
+
322
+ **Mitigation**:
323
+
324
+ ```ruby
325
+ # OpaqueId uses constant-time operations
326
+ # SecureRandom provides timing-attack resistance
327
+ # No predictable patterns in generation
328
+ ```
329
+
330
+ **Analysis**:
331
+
332
+ - Bitwise operations have predictable timing
333
+ - Rejection sampling doesn't leak information
334
+ - SecureRandom prevents timing-based prediction
335
+
336
+ #### 3. Statistical Attacks
337
+
338
+ **Threat**: Attackers analyze patterns in generated IDs
339
+
340
+ **Mitigation**:
341
+
342
+ ```ruby
343
+ # Uniform distribution through rejection sampling
344
+ # Cryptographically secure randomness
345
+ # No statistical patterns
346
+ ```
347
+
348
+ **Analysis**:
349
+
350
+ - Rejection sampling ensures uniform distribution
351
+ - SecureRandom prevents pattern detection
352
+ - High entropy prevents statistical analysis
353
+
354
+ #### 4. Collision Attacks
355
+
356
+ **Threat**: Attackers attempt to generate duplicate IDs
357
+
358
+ **Mitigation**:
359
+
360
+ ```ruby
361
+ # Built-in collision detection
362
+ self.opaque_id_max_retry = 5
363
+
364
+ # Database constraints
365
+ add_index :users, :opaque_id, unique: true
366
+
367
+ # Monitor for collision attempts
368
+ ```
369
+
370
+ **Analysis**:
371
+
372
+ - Collision probability: 2.3×10⁻¹⁵ (1M IDs)
373
+ - Automatic retry on collision
374
+ - Database constraints prevent duplicates
375
+
376
+ ### Security Audit Checklist
377
+
378
+ #### ✅ Cryptographic Security
379
+
380
+ - [ ] Uses `SecureRandom` for all random generation
381
+ - [ ] No predictable patterns in ID generation
382
+ - [ ] Sufficient entropy for security requirements
383
+ - [ ] No timing attack vulnerabilities
384
+
385
+ #### ✅ Access Control
386
+
387
+ - [ ] Proper authentication on all endpoints
388
+ - [ ] Authorization checks for ID access
389
+ - [ ] Rate limiting implemented
390
+ - [ ] Input validation on all parameters
391
+
392
+ #### ✅ Data Protection
393
+
394
+ - [ ] Opaque IDs not logged in plaintext
395
+ - [ ] HTTPS used for all transmissions
396
+ - [ ] Proper CORS policies implemented
397
+ - [ ] Sensitive data not exposed in URLs
398
+
399
+ #### ✅ Monitoring
400
+
401
+ - [ ] Logging of suspicious activity
402
+ - [ ] Monitoring for brute force attempts
403
+ - [ ] Alerting on security events
404
+ - [ ] Regular security audits
405
+
406
+ #### ✅ Configuration
407
+
408
+ - [ ] Appropriate ID length for security level
409
+ - [ ] Secure alphabet selection
410
+ - [ ] Proper collision handling
411
+ - [ ] Error handling for generation failures
412
+
413
+ ## Implementation Security
414
+
415
+ ### Secure Generation
416
+
417
+ ```ruby
418
+ class SecureIdGenerator
419
+ def self.generate_secure_id(length: 21, alphabet: OpaqueId::ALPHANUMERIC_ALPHABET)
420
+ # Validate parameters
421
+ raise ArgumentError, "Length must be positive" unless length.positive?
422
+ raise ArgumentError, "Alphabet cannot be empty" if alphabet.nil? || alphabet.empty?
423
+
424
+ # Generate secure ID
425
+ OpaqueId.generate(size: length, alphabet: alphabet)
426
+ rescue => e
427
+ # Log security events
428
+ Rails.logger.error "Secure ID generation failed: #{e.message}"
429
+ raise
430
+ end
431
+ end
432
+ ```
433
+
434
+ ### Secure Storage
435
+
436
+ ```ruby
437
+ # Database security
438
+ class AddOpaqueIdToUsers < ActiveRecord::Migration[8.0]
439
+ def change
440
+ add_column :users, :opaque_id, :string, null: false
441
+ add_index :users, :opaque_id, unique: true
442
+
443
+ # Additional security constraints
444
+ add_check_constraint :users, "length(opaque_id) >= 8", name: "opaque_id_length_check"
445
+ end
446
+ end
447
+ ```
448
+
449
+ ### Secure Access
450
+
451
+ ```ruby
452
+ class UsersController < ApplicationController
453
+ before_action :authenticate_user!
454
+ before_action :authorize_user_access!
455
+
456
+ def show
457
+ @user = User.find_by_opaque_id!(params[:id])
458
+
459
+ # Additional security checks
460
+ unless current_user.can_access?(@user)
461
+ raise SecurityError, "Unauthorized access attempt"
462
+ end
463
+ end
464
+
465
+ private
466
+
467
+ def authorize_user_access!
468
+ # Implement proper authorization
469
+ # Check user permissions
470
+ # Validate access rights
471
+ end
472
+ end
473
+ ```
474
+
475
+ ## Security Monitoring
476
+
477
+ ### Logging Security Events
478
+
479
+ ```ruby
480
+ class SecurityLogger
481
+ def self.log_id_generation(user_id, opaque_id_length)
482
+ Rails.logger.info "Generated opaque ID for user #{user_id}, length: #{opaque_id_length}"
483
+ end
484
+
485
+ def self.log_suspicious_activity(ip_address, user_agent, opaque_id)
486
+ Rails.logger.warn "Suspicious activity detected: IP #{ip_address}, UA #{user_agent}, ID #{opaque_id}"
487
+ end
488
+
489
+ def self.log_collision_attempt(opaque_id, retry_count)
490
+ Rails.logger.error "Collision detected: ID #{opaque_id}, retry #{retry_count}"
491
+ end
492
+ end
493
+ ```
494
+
495
+ ### Monitoring and Alerting
496
+
497
+ ```ruby
498
+ class SecurityMonitor
499
+ def self.monitor_brute_force_attempts
500
+ # Monitor for rapid ID generation attempts
501
+ # Alert on suspicious patterns
502
+ # Block malicious IPs
503
+ end
504
+
505
+ def self.monitor_collision_attempts
506
+ # Monitor for collision attempts
507
+ # Alert on high collision rates
508
+ # Investigate potential attacks
509
+ end
510
+
511
+ def self.monitor_access_patterns
512
+ # Monitor access patterns
513
+ # Detect unusual behavior
514
+ # Alert on security violations
515
+ end
516
+ end
517
+ ```
518
+
519
+ ## Compliance and Standards
520
+
521
+ ### Security Standards
522
+
523
+ OpaqueId complies with various security standards:
524
+
525
+ - **FIPS 140-2**: Uses approved random number generators
526
+ - **Common Criteria**: Provides security functionality
527
+ - **ISO 27001**: Implements security controls
528
+ - **SOC 2**: Meets security requirements
529
+
530
+ ### Compliance Requirements
531
+
532
+ ```ruby
533
+ # HIPAA compliance for healthcare applications
534
+ class Patient < ApplicationRecord
535
+ include OpaqueId::Model
536
+
537
+ # High entropy for patient data
538
+ self.opaque_id_length = 32
539
+ self.opaque_id_alphabet = OpaqueId::ALPHANUMERIC_ALPHABET
540
+
541
+ # Audit logging
542
+ after_create :log_patient_id_generation
543
+
544
+ private
545
+
546
+ def log_patient_id_generation
547
+ AuditLog.create!(
548
+ action: 'patient_id_generated',
549
+ patient_id: id,
550
+ opaque_id: opaque_id,
551
+ timestamp: Time.current
552
+ )
553
+ end
554
+ end
555
+ ```
556
+
557
+ ## Best Practices Summary
558
+
559
+ ### 1. Choose Appropriate Security Level
560
+
561
+ ```ruby
562
+ # High security: 21+ characters, 125+ bits entropy
563
+ # Medium security: 15+ characters, 60+ bits entropy
564
+ # Low security: 8+ characters, 40+ bits entropy
565
+ ```
566
+
567
+ ### 2. Implement Defense in Depth
568
+
569
+ ```ruby
570
+ # Multiple security layers
571
+ # Authentication + Authorization
572
+ # Rate limiting + Monitoring
573
+ # Encryption + Audit logging
574
+ ```
575
+
576
+ ### 3. Monitor and Alert
577
+
578
+ ```ruby
579
+ # Log security events
580
+ # Monitor for attacks
581
+ # Alert on violations
582
+ # Regular security audits
583
+ ```
584
+
585
+ ### 4. Follow Security Standards
586
+
587
+ ```ruby
588
+ # Use HTTPS
589
+ # Implement proper access controls
590
+ # Follow OWASP guidelines
591
+ # Regular security updates
592
+ ```
593
+
594
+ ## Next Steps
595
+
596
+ Now that you understand security considerations:
597
+
598
+ 1. **Explore [Performance](performance.md)** for security-performance trade-offs
599
+ 2. **Check out [Algorithms](algorithms.md)** for technical security details
600
+ 3. **Review [Configuration](configuration.md)** for secure configuration options
601
+ 4. **Read [API Reference](api-reference.md)** for complete security documentation