robust_server_socket 0.4.2 → 0.4.3

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/README.en.md CHANGED
@@ -17,6 +17,8 @@ When building microservice architecture, the server side faces:
17
17
  - **DDoS attacks**: Need to limit request frequency
18
18
  - **Boilerplate code**: Repetitive validation logic in every service
19
19
 
20
+ #### Even if infrastructure is behind a DMZ in a private network, there is still room for SSRF or OpenRedirect attacks
21
+
20
22
  ### The Solution
21
23
 
22
24
  RobustServerSocket provides:
@@ -24,7 +26,7 @@ RobustServerSocket provides:
24
26
  - **RSA decryption**: Token authenticity verification
25
27
  - **Client whitelist**: Only authorized services allowed
26
28
  - **Replay protection**: Blacklist of used tokens in Redis
27
- - **Rate limiting**: Per-client request limits
29
+ - **Rate limiting**: Sliding window per-client request limits
28
30
 
29
31
  ## HOW IT WORKS
30
32
 
@@ -54,18 +56,18 @@ Incoming request with Secure-Token
54
56
  ### Validation Flow
55
57
 
56
58
  1. **Decryption**: Base64 decode → RSA decrypt with private key
57
- 2. **Parsing**: Extract `{client_name}_{timestamp}` from token
59
+ 2. **Parsing**: Extract `{client_name}_{timestamp_ms}` from token
58
60
  3. **Whitelist**: Verify client_name is in `allowed_services`
59
- 4. **Rate limit**: Check request count within window
61
+ 4. **Rate limit**: Sliding window — check request count within `rate_limit_window_seconds`
60
62
  5. **Replay check**: Verify token hasn't been used (Redis)
61
- 6. **Staleness**: Verify timestamp is current
63
+ 6. **Staleness**: Verify timestamp is current (with ±30s clock skew tolerance)
62
64
 
63
65
  ### Modular System
64
66
 
65
67
  Checks are enabled via `using_modules`:
66
68
  - `:client_auth_protection` — client whitelist
67
69
  - `:replay_attack_protection` — prevent token reuse
68
- - `:dos_attack_protection` — rate limiting
70
+ - `:rate_limit_protection` — sliding window rate limiting
69
71
 
70
72
  ## 📋 Table of Contents
71
73
 
@@ -82,28 +84,25 @@ RobustServerSocket implements a multi-layered protection system for inter-servic
82
84
  ### 1. Cryptographic Protection
83
85
  - **RSA-2048 Encryption**: Uses RSA key pairs with minimum 2048-bit length
84
86
  - **Key Validation**: Automatic key size verification during configuration
85
- - **Asymmetric Encryption**: Private key on server, public keys on clients
86
87
 
87
- ### 2. Token Reuse Protection
88
- - **One-time Tokens**: Each token can only be used once
89
- - **Redis Blacklist**: Used tokens are automatically added to blacklist
90
- - **Atomic Verification**: Race conditions prevented via Redis Lua scripts
88
+ ### 2. Access Control
89
+ - **Client Whitelist**: Only authorized services can connect, when `:client_auth_protection` module is enabled
90
+ - **Name-based Identification**: Each client must be explicitly listed in `allowed_services`
91
91
 
92
- ### 3. Time-based Restrictions
93
- - **Expiration Time**: Configurable token lifetime
94
- - **Automatic Expiration**: Tokens automatically become invalid after expiration
95
- - **Replay Attack Protection**: Old tokens cannot be reused
92
+ ### 3. Replay Attack Protection
93
+ - **One-time Tokens**: Used tokens are added to a Redis blacklist, when `:replay_attack_protection` is enabled
94
+ - **Staleness Check**: Tokens automatically become invalid after `token_expiration_time`
95
+ - **Clock Skew Tolerance**: ±30 seconds (CLOCK_SKEW)
96
+ - **Blacklist TTL**: Computed automatically as `token_expiration_time + CLOCK_SKEW`
96
97
 
97
- ### 4. Access Control
98
- - **Client Whitelist**: Only authorized services can connect
99
- - **Name-based Identification**: Each client must be explicitly listed in `allowed_services`
100
- - **Token Format Validation**: Strict token structure verification
98
+ ### 4. Rate Limiting
99
+ - **Sliding Window**: When `:rate_limit_protection` is enabled — precise request counting without the burst effect of fixed windows
100
+ - **Fail-open Strategy**: If Redis is unavailable, requests are allowed through (for service reliability)
101
+ - **Per-client Isolation**: Counter is tracked individually per `client_name`
101
102
 
102
- ### 5. Rate Limiting (optional)
103
- - **DDoS Protection**: Limit number of requests from each client
104
- - **Sliding Window**: Fair distribution of requests over time
105
- - **Fail-open Strategy**: If Redis is unavailable, requests are allowed (for reliability)
106
- - **Per-client Limits**: Individual counters for each client
103
+ ### 5. SSL Stripping / MITM Protection
104
+ - **Enforce HTTPS on server**: All requests should be made over HTTPS to protect tokens from interception
105
+ - **Enabled on RobustClientSocket with `ssl_verify: true`**
107
106
 
108
107
  ### 6. Injection Protection
109
108
  - **Input Validation**: Type, length, and format verification of tokens
@@ -112,16 +111,13 @@ RobustServerSocket implements a multi-layered protection system for inter-servic
112
111
 
113
112
  ## 📦 Installation
114
113
 
115
- Add to Gemfile:
116
-
117
114
  ```ruby
118
115
  gem 'robust_server_socket'
119
116
  ```
120
117
 
121
- Then execute:
122
-
123
- ```bash
124
- bundle install
118
+ and on the client:
119
+ ```ruby
120
+ gem 'robust_client_socket'
125
121
  ```
126
122
 
127
123
  ## ⚙️ Configuration
@@ -130,125 +126,120 @@ Create file `config/initializers/robust_server_socket.rb`:
130
126
 
131
127
  ```ruby
132
128
  RobustServerSocket.configure do |c|
133
- # REQUIRED PARAMETERS
134
-
129
+ c.using_modules = %i[
130
+ client_auth_protection
131
+ replay_attack_protection
132
+ rate_limit_protection
133
+ ]
134
+
135
135
  # Service private key (RSA-2048 or higher)
136
- # IMPORTANT: Store in environment variables, DO NOT commit to git!
137
136
  c.private_key = ENV['ROBUST_SERVER_PRIVATE_KEY']
138
-
139
- # Token lifetime in seconds
140
- # Recommendation: 1-3 seconds for production (time from client request to server)
141
- c.token_expiration_time = 3
142
-
137
+
138
+ # Token lifetime in seconds (must match TTL on client side)
139
+ c.token_expiration_time = 10
140
+
143
141
  # List of allowed services (whitelist)
144
- # Must match names in client keychain
142
+ # Must match service_name in RobustClientSocket
145
143
  c.allowed_services = %w[core payments notifications]
146
-
147
- # Redis for storing used tokens
144
+
145
+ # Redis for replay_attack_protection and rate_limit_protection
148
146
  c.redis_url = ENV.fetch('REDIS_URL', 'redis://localhost:6379/0')
149
- c.redis_pass = ENV['REDIS_PASSWORD'] # can be nil for local development
147
+ c.redis_pass = ENV['REDIS_PASSWORD']
150
148
 
151
- # Maximum requests per time window (default: 100)
152
- c.rate_limit_max_requests = 100
153
-
154
- # Time window size in seconds (default: 60)
155
- c.rate_limit_window_seconds = 60
149
+ # rate_limit_protection
150
+ c.rate_limit_max_requests = 100 # max requests per window (default: 100)
151
+ c.rate_limit_window_seconds = 60 # window size in seconds (default: 60)
156
152
  end
157
153
 
158
- # Load configuration with validation
159
154
  RobustServerSocket.load!
160
155
  ```
161
156
 
157
+ ### Configuration Options
158
+
159
+ | Parameter | Type | Required | Default | Description |
160
+ |-----------------------------|---------|----------|-------------------------------------------------------------------------------------|-------------------------------------------------|
161
+ | `private_key` | String | ✅ | — | Service private RSA key (RSA-2048 or higher) |
162
+ | `token_expiration_time` | Integer | ✅ | 10 | Token lifetime in seconds |
163
+ | `allowed_services` | Array | ✅ | — | Allowed services whitelist |
164
+ | `redis_url` | String | ✅ | — | Redis connection URL |
165
+ | `redis_pass` | String | ❌ | nil | Redis password |
166
+ | `using_modules` | Array | ❌ | `[:client_auth_protection, :rate_limit_protection, :replay_attack_protection]` | Enabled modules |
167
+ | `rate_limit_max_requests` | Integer | ❌ | 100 | Max requests per window |
168
+ | `rate_limit_window_seconds` | Integer | ❌ | 60 | Window size in seconds |
169
+
170
+ > `store_used_token_time` is no longer configurable — computed automatically as `token_expiration_time + 30` (CLOCK_SKEW).
171
+
172
+ ### Compatibility with RobustClientSocket
173
+
174
+ The token contains a timestamp in **milliseconds**. RobustClientSocket starting from version X.X must generate:
175
+
176
+ ```ruby
177
+ Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond)
178
+ ```
179
+
180
+ The legacy `Time.now.utc.to_i` (seconds) will cause all tokens to be rejected as `stale`.
181
+
162
182
  ## 🚀 Usage
163
183
 
164
184
  ### Basic Authorization
165
185
 
166
186
  ```ruby
167
- # In controller or middleware
168
187
  class ApiController < ApplicationController
169
188
  before_action :authenticate_service!
170
-
189
+
171
190
  private
172
-
191
+
173
192
  def authenticate_service!
174
- # Header configured in RobustClientSocket (SECURE-TOKEN default)
175
193
  token = request.headers['SECURE-TOKEN']&.sub(/^Bearer /, '')
176
-
177
- @current_service = RobustServerSocket::ClientToken.validate!(token) # bang method (raises errors)
194
+ @current_service = RobustServerSocket::ClientToken.validate!(token)
178
195
  rescue RobustServerSocket::ClientToken::InvalidToken
179
196
  render json: { error: 'Invalid token' }, status: :unauthorized
180
- rescue RobustServerSocket::ClientToken::UnauthorizedClient
197
+ rescue RobustServerSocket::Modules::ClientAuthProtection::UnauthorizedClient
181
198
  render json: { error: 'Unauthorized service' }, status: :forbidden
182
- rescue RobustServerSocket::ClientToken::UsedToken
199
+ rescue RobustServerSocket::Modules::ReplayAttackProtection::UsedToken
183
200
  render json: { error: 'Token already used' }, status: :unauthorized
184
- rescue RobustServerSocket::ClientToken::StaleToken
201
+ rescue RobustServerSocket::Modules::ReplayAttackProtection::StaleToken
185
202
  render json: { error: 'Token expired' }, status: :unauthorized
186
203
  rescue RobustServerSocket::RateLimiter::RateLimitExceeded => e
187
204
  render json: { error: e.message }, status: :too_many_requests
188
205
  end
189
-
190
- def authenticate_service
191
- token = request.headers['SECURE-TOKEN']&.sub(/^Bearer /, '')
192
- @current_service = RobustServerSocket::ClientToken.new(token)
193
-
194
- if @current_service.valid? # doesn't raise errors
195
- # Token is valid
196
- else
197
- # Token is invalid
198
- render json: { error: 'Unauthorized' }, status: :unauthorized
199
- end
200
- end
201
206
  end
202
207
  ```
203
208
 
204
- ### Advanced Usage
209
+ ### valid? (non-raising)
205
210
 
206
211
  ```ruby
207
- # Create token object
208
- token_string = request.headers['SECURE-TOKEN']&.sub(/^Bearer /, '')
209
- client_token = RobustServerSocket::ClientToken.new(token_string)
212
+ token = request.headers['SECURE-TOKEN']&.sub(/^Bearer /, '')
213
+ client_token = RobustServerSocket::ClientToken.new(token)
210
214
 
211
- # Check validity (returns true/false)
212
215
  if client_token.valid?
213
- # Get client name
214
216
  client_name = client_token.client
215
- puts "Authorized client: #{client_name}"
216
217
  else
217
- # Token is invalid
218
218
  render json: { error: 'Unauthorized' }, status: :unauthorized
219
219
  end
220
-
221
- # Quick validation with exceptions (recommended)
222
- begin
223
- service_token = RobustServerSocket::ClientToken.validate!(token_string)
224
- client_name = service_token.client
225
- rescue => e
226
- # Handle specific errors
227
- end
228
220
  ```
229
221
 
230
222
  ## ❌ Error Handling
231
223
 
232
224
  ### Exception Types
233
225
 
234
- | Exception | Reason | HTTP Status | Action |
235
- |-----------|--------|-------------|--------|
236
- | `InvalidToken` | Token cannot be decrypted or has invalid format | 401 | Check token and key correctness |
237
- | `UnauthorizedClient` | Client not in whitelist | 403 | Add client to `allowed_services` |
238
- | `UsedToken` | Token has already been used | 401 | Client must request new token |
239
- | `StaleToken` | Token has expired | 401 | Client must request new token |
240
- | `RateLimitExceeded` | Rate limit exceeded | 429 | Client should wait or retry later |
226
+ | Exception | Reason | HTTP Status |
227
+ |------------------------------------------------------------|-------------------------------------------|-------------|
228
+ | `ClientToken::InvalidToken` | Token cannot be decrypted or wrong format | 401 |
229
+ | `Modules::ClientAuthProtection::UnauthorizedClient` | Client not in whitelist | 403 |
230
+ | `Modules::ReplayAttackProtection::UsedToken` | Token has already been used | 401 |
231
+ | `Modules::ReplayAttackProtection::StaleToken` | Token expired or from the future (>30s) | 401 |
232
+ | `RateLimiter::RateLimitExceeded` | Rate limit exceeded | 429 |
241
233
 
242
234
  ### Centralized Error Handling
243
235
 
244
236
  ```ruby
245
- # In ApplicationController
246
237
  rescue_from RobustServerSocket::ClientToken::InvalidToken,
247
- RobustServerSocket::ClientToken::UsedToken,
248
- RobustServerSocket::ClientToken::StaleToken,
238
+ RobustServerSocket::Modules::ReplayAttackProtection::UsedToken,
239
+ RobustServerSocket::Modules::ReplayAttackProtection::StaleToken,
249
240
  with: :unauthorized_response
250
241
 
251
- rescue_from RobustServerSocket::ClientToken::UnauthorizedClient,
242
+ rescue_from RobustServerSocket::Modules::ClientAuthProtection::UnauthorizedClient,
252
243
  with: :forbidden_response
253
244
 
254
245
  rescue_from RobustServerSocket::RateLimiter::RateLimitExceeded,
@@ -257,80 +248,24 @@ rescue_from RobustServerSocket::RateLimiter::RateLimitExceeded,
257
248
  private
258
249
 
259
250
  def unauthorized_response(exception)
260
- render json: {
261
- error: 'Authentication failed',
262
- message: exception.message,
263
- type: exception.class.name
264
- }, status: :unauthorized
251
+ render json: { error: 'Authentication failed', message: exception.message }, status: :unauthorized
265
252
  end
266
253
 
267
254
  def forbidden_response(exception)
268
- render json: {
269
- error: 'Access denied',
270
- message: exception.message,
271
- type: exception.class.name
272
- }, status: :forbidden
255
+ render json: { error: 'Access denied', message: exception.message }, status: :forbidden
273
256
  end
274
257
 
275
258
  def rate_limit_response(exception)
276
259
  render json: {
277
260
  error: 'Too many requests',
278
261
  message: exception.message,
279
- type: exception.class.name,
280
262
  retry_after: RobustServerSocket.configuration.rate_limit_window_seconds
281
263
  }, status: :too_many_requests
282
264
  end
283
265
  ```
284
266
 
285
- ### 2. Redis Configuration
286
-
287
- **✅ DO:**
288
- ```ruby
289
- # Use separate namespace for each environment
290
- c.redis_url = ENV.fetch('REDIS_URL', 'redis://localhost:6379/0')
291
-
292
- # Configure connection pool in production
293
- # In config/initializers/redis.rb
294
- Redis.current = ConnectionPool.new(size: 5, timeout: 5) do
295
- Redis.new(url: ENV['REDIS_URL'], password: ENV['REDIS_PASSWORD'])
296
- end
297
-
298
- # Monitor Redis status
299
- # Use Redis Sentinel or Cluster for high availability
300
- ```
301
-
302
- **❌ DON'T:**
303
- ```ruby
304
- # DON'T use same Redis DB for all environments, use separate Redis DB
305
- # DON'T ignore Redis errors (rate limiter is already fail-open, but log them)
306
- ```
307
-
308
- ### 5. Service Whitelist
309
-
310
- ```ruby
311
- # Explicitly specify only necessary services
312
- c.allowed_services = %w[core payments] # ✅
313
-
314
- # DON'T use wildcards or regular expressions
315
- c.allowed_services = %w[*] # ❌ DANGEROUS!
316
-
317
- # Synchronize with client keychain
318
- # Server (robust_server_socket):
319
- c.allowed_services = %w[core]
320
-
321
- # Client (robust_client_socket):
322
- c.keychain = {
323
- core: { # ← Must match
324
- base_uri: 'https://core.example.com',
325
- public_key: '-----BEGIN PUBLIC KEY-----...'
326
- }
327
- }
328
- ```
329
-
330
267
  ## 🤝 Integration with RobustClientSocket
331
268
 
332
- For full functionality, configure the client side:
333
-
334
269
  ```ruby
335
270
  # On client (RobustClientSocket)
336
271
  RobustClientSocket.configure do |c|
@@ -338,270 +273,49 @@ RobustClientSocket.configure do |c|
338
273
  c.keychain = {
339
274
  payments: {
340
275
  base_uri: 'https://payments.example.com',
341
- public_key: '-----BEGIN PUBLIC KEY-----...' # Public key of payments server
276
+ public_key: '-----BEGIN PUBLIC KEY-----...'
342
277
  }
343
278
  }
344
279
  end
345
280
 
346
281
  # On server (RobustServerSocket)
347
282
  RobustServerSocket.configure do |c|
348
- c.allowed_services = %w[core] # ← Matches client's service_name
349
- c.private_key = '-----BEGIN PRIVATE KEY-----...' # Private pair to public_key
283
+ c.allowed_services = %w[core]
284
+ c.private_key = '-----BEGIN PRIVATE KEY-----...'
350
285
  end
351
286
  ```
352
287
 
353
- ## 📚 Additional Resources
354
-
355
- - [RobustClientSocket documentation](https://github.com/tee0zed/robust_client_socket)
356
- - [RSA encryption best practices](https://www.openssl.org/docs/)
357
- - [Redis security guide](https://redis.io/topics/security)
358
-
359
- ## 📝 License
288
+ ## 📊 Performance
360
289
 
361
- See [MIT-LICENSE](MIT-LICENSE) file
362
-
363
- ## 🐛 Bugs and Suggestions
364
-
365
- Report issues through your repository's issue tracker.
366
-
367
-
368
- #### Test: 1000 Requests with Token Validation
290
+ ### Benchmark: 1000 Requests with Token Validation
369
291
 
370
292
  **Without RobustServerSocket (plain HTTP controller):**
371
- ```ruby
372
- Benchmark.measure do
373
- 1000.times do
374
- # Regular request without authorization
375
- get '/api/v1/partners/719a68e4-3457-45dd-8d7f-73f1d367b87a/merchants'
376
- end
377
- end
378
- ```
379
-
380
- **Results (approximate):**
381
- - **Real time**: ~2.5 seconds
382
- - No token verification
383
- - No RSA decryption
384
- - No Redis checks
385
-
386
- ---
293
+ - Real time: ~2.5 seconds
294
+ - No token verification, no RSA decryption, no Redis checks
387
295
 
388
296
  **With RobustServerSocket (full protection):**
389
- ```ruby
390
- Benchmark.measure do
391
- 1000.times do
392
- # Request with RobustClientSocket (RSA + tokens)
393
- RobustClientSocket::CoreApi.get('/api/v1/partners/719a68e4-3457-45dd-8d7f-73f1d367b87a/merchants')
394
- end
395
- end
396
- ```
397
-
398
- **Results:**
399
- - **Real time**: 2.77 seconds
400
- - **User CPU**: 0.23 seconds
401
- - **System CPU**: 0.54 seconds
402
- - **Total CPU**: 0.77 seconds
403
-
404
- ### 📊 Security Overhead Analysis
405
-
406
- | Operation | Time | % of Request |
407
- |-----------|------|-------------|
408
- | **RSA Decryption** | ~0.1-0.2ms | 3-7% |
409
- | **Redis Token Check** | ~0.05-0.1ms | 2-3% |
410
- | **Rate Limiting** | ~0.02-0.05ms | 1% |
411
- | **Whitelist Validation** | <0.01ms | <1% |
412
- | **Total Overhead** | **~0.2-0.4ms** | **~10-15%** |
413
-
414
- ### 🎯 Key Findings
415
-
416
- 1. **Minimal overhead (~0.3ms per request)**
417
- - RSA-2048 decryption: ~0.15ms
418
- - Redis operations: ~0.08ms
419
- - Rate limiting: ~0.03ms
420
-
421
- 2. **Scales linearly**
422
- - 100 req/s = +30ms overhead
423
- - 1000 req/s = +300ms overhead
424
- - Acceptable for most applications
425
-
426
- 3. **Redis is main bottleneck**
427
- - Use Redis Sentinel/Cluster
428
- - Connection pooling is critical
429
- - Fail-open strategy for reliability
430
-
431
- ### 💡 Performance Optimization
432
-
433
- **1. Redis Connection Pool:**
434
-
435
- ```ruby
436
- # config/initializers/redis.rb
437
- require 'connection_pool'
438
-
439
- REDIS_POOL = ConnectionPool.new(size: 25, timeout: 5) do
440
- Redis.new(
441
- url: ENV['REDIS_URL'],
442
- password: ENV['REDIS_PASSWORD'],
443
- reconnect_attempts: 3,
444
- reconnect_delay: 0.5,
445
- reconnect_delay_max: 5.0
446
- )
447
- end
448
-
449
- # In RobustServerSocket::Cacher
450
- def self.with_redis
451
- REDIS_POOL.with do |redis|
452
- yield redis
453
- end
454
- end
455
- ```
456
-
457
- **2. Public Key Caching:**
458
-
459
- ```ruby
460
- # Keys are already cached at load!, but can be optimized
461
- class RobustServerSocket::ClientToken
462
- # Keys are loaded once at application startup
463
- # No additional optimization needed
464
- end
465
- ```
466
-
467
- **3. Rate Limiting Optimization:**
468
-
469
- ```ruby
470
- RobustServerSocket.configure do |c|
471
- # For high-load systems
472
- c.rate_limit_max_requests = 1000 # Increase limit
473
- c.rate_limit_window_seconds = 60
474
-
475
- # For low-load systems
476
- c.rate_limit_max_requests = 100
477
- c.rate_limit_window_seconds = 60
478
- end
479
- ```
480
-
481
- **4. Token Expiration Optimization:**
482
-
483
- ```ruby
484
- # Short lifetime = more requests for new tokens
485
- c.token_expiration_time = 10.minutes # ❌ High traffic
486
-
487
- # Optimal time for inter-service calls
488
- c.token_expiration_time = 3 # ✅ 3 seconds is enough
489
- ```
490
-
491
- ### 🔬 Performance Monitoring
492
-
493
- **Metrics to Track:**
297
+ - Real time: ~2.77 seconds
298
+ - User CPU: 0.23s, System CPU: 0.54s
494
299
 
495
- ```ruby
496
- class ApiController < ApplicationController
497
- around_action :track_auth_performance
498
-
499
- private
500
-
501
- def track_auth_performance
502
- start = Time.now
503
-
504
- begin
505
- yield
506
- ensure
507
- duration = ((Time.now - start) * 1000).round(2)
508
-
509
- # Total request time
510
- Metrics.timing('request.duration', duration, tags: [
511
- "controller:#{controller_name}",
512
- "action:#{action_name}"
513
- ])
514
-
515
- # Authentication attempts
516
- if @current_service
517
- Metrics.increment('auth.success', tags: ["service:#{@current_service.client}"])
518
- else
519
- Metrics.increment('auth.failure')
520
- end
521
- end
522
- end
523
- end
524
-
525
- # Specific metrics for RobustServerSocket
526
- module RobustServerSocket
527
- class ClientToken
528
- def self.validate_with_metrics!(token)
529
- start = Time.now
530
- result = validate!(token)
531
- duration = ((Time.now - start) * 1000).round(2)
532
-
533
- Metrics.timing('robust_server.validation.duration', duration)
534
- result
535
- rescue StandardError => e
536
- Metrics.increment('robust_server.validation.error', tags: ["error:#{e.class.name}"])
537
- raise
538
- end
539
- end
540
- end
541
- ```
542
-
543
- ### 📈 Performance at Different Loads
544
-
545
- | Req/s | Without Protection | With RobustServerSocket | Overhead | Acceptable |
546
- |-------|-------------------|------------------------|----------|-----------|
547
- | 10 | 100ms | 103ms | 3ms | ✅ Excellent |
548
- | 100 | 1s | 1.03s | 30ms | ✅ Excellent |
549
- | 500 | 5s | 5.15s | 150ms | ✅ Good |
550
- | 1,000 | 10s | 10.3s | 300ms | ✅ Acceptable |
551
- | 5,000 | 50s | 51.5s | 1.5s | ⚠️ Redis scaling needed |
552
- | 10,000 | 100s | 103s | 3s | ⚠️ Need Redis Cluster |
553
-
554
- **Conclusion:** Up to 1000 req/s - excellent performance. Higher loads require Redis scaling.
555
-
556
- ### 🚀 Production Recommendations
557
-
558
- **For high-load systems (>1000 req/s):**
559
-
560
- 1. **Redis Cluster** - distributed load
561
- 2. **Connection Pool** - minimum 25-50 connections
562
- 3. **Monitor Redis** - latency, memory, connections
563
- 4. **Fail-over Strategy** - Redis Sentinel
564
- 5. **CDN for static** - reduce overall load
565
-
566
- **For medium load (100-1000 req/s):**
567
-
568
- 1. **Standalone Redis** with persistence
569
- 2. **Connection Pool** - 10-25 connections
570
- 3. **Basic monitoring**
571
- 4. **Rate limiting** - spike protection
300
+ ### Security Overhead Analysis
572
301
 
573
- **For low load (<100 req/s):**
302
+ | Operation | Time | % of Request |
303
+ |------------------------|-------------|-------------|
304
+ | RSA Decryption | ~0.1–0.2ms | 3–7% |
305
+ | Redis Token Check | ~0.05–0.1ms | 2–3% |
306
+ | Rate Limiting | ~0.02–0.05ms| 1% |
307
+ | Whitelist Validation | <0.01ms | <1% |
308
+ | **Total Overhead** | **~0.2–0.4ms** | **~10–15%** |
574
309
 
575
- 1. **Simple Redis** setup
576
- 2. **Default connection pool** (5)
577
- 3. **Standard configuration**
310
+ Up to 1000 req/s — excellent performance. Higher loads require Redis Sentinel/Cluster.
578
311
 
579
- ## 🤝 Integration with RobustClientSocket
580
-
581
- For full functionality, configure the client side:
312
+ ## 🗺️ TODO
582
313
 
583
- ```ruby
584
- # On client (RobustClientSocket)
585
- RobustClientSocket.configure do |c|
586
- c.service_name = 'core' # ← Must be in server's allowed_services
587
- c.keychain = {
588
- payments: {
589
- base_uri: 'https://payments.example.com',
590
- public_key: '-----BEGIN PUBLIC KEY-----...' # Public key of payments server
591
- }
592
- }
593
- end
594
-
595
- # On server (RobustServerSocket)
596
- RobustServerSocket.configure do |c|
597
- c.allowed_services = %w[core] # ← Matches client's service_name
598
- c.private_key = '-----BEGIN PRIVATE KEY-----...' # Private pair to public_key
599
- end
600
- ```
314
+ - [ ] **Per-client rate limit keys** — configurable individual limits per `client_name` instead of a single global limit
601
315
 
602
316
  ## 📚 Additional Resources
603
317
 
604
- - [RobustClientSocket documentation](../robust_client_socket/README.md)
318
+ - [RobustClientSocket](https://github.com/tee0zed/robust_client_socket)
605
319
  - [RSA encryption best practices](https://www.openssl.org/docs/)
606
320
  - [Redis security guide](https://redis.io/topics/security)
607
321
 
@@ -611,4 +325,4 @@ See [MIT-LICENSE](MIT-LICENSE) file
611
325
 
612
326
  ## 🐛 Bugs and Suggestions
613
327
 
614
- Report issues to my telegram @cruel_mango or to email tee0zed@gmail.com
328
+ Report issues via GitHub issues, or directly at Telegram @cruel_mango or email tee0zed@gmail.com