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