1use crate::security::compression_bomb::CompressionBombConfig;
4use serde::{Deserialize, Serialize};
5use std::time::Duration;
6
7#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9pub struct SecurityConfig {
10 pub json: JsonLimits,
12
13 pub buffers: BufferLimits,
15
16 pub network: NetworkLimits,
18
19 pub sessions: SessionLimits,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct JsonLimits {
26 pub max_input_size: usize,
28
29 pub max_depth: usize,
31
32 pub max_object_keys: usize,
34
35 pub max_array_length: usize,
37
38 pub max_string_length: usize,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct BufferLimits {
45 pub max_buffer_size: usize,
47
48 pub max_pool_size: usize,
50
51 pub max_total_memory: usize,
53
54 pub buffer_ttl_secs: u64,
56
57 pub max_buffers_per_bucket: usize,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct NetworkLimits {
64 pub max_websocket_frame_size: usize,
66
67 pub max_concurrent_connections: usize,
69
70 pub connection_timeout_secs: u64,
72
73 pub max_requests_per_second: u32,
75
76 pub max_http_payload_size: usize,
78
79 pub rate_limiting: RateLimitingConfig,
81
82 pub compression_bomb: CompressionBombConfig,
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct RateLimitingConfig {
89 pub max_requests_per_window: u32,
91
92 pub window_duration_secs: u64,
94
95 pub max_connections_per_ip: usize,
97
98 pub max_messages_per_second: u32,
100
101 pub burst_allowance: u32,
103
104 pub enabled: bool,
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
110pub struct SessionLimits {
111 pub max_session_id_length: usize,
113
114 pub min_session_id_length: usize,
116
117 pub max_streams_per_session: usize,
119
120 pub session_timeout_secs: u64,
122
123 pub max_session_data_size: usize,
125}
126
127impl Default for JsonLimits {
128 fn default() -> Self {
129 Self {
130 max_input_size: 100 * 1024 * 1024, max_depth: 64,
132 max_object_keys: 10_000,
133 max_array_length: 1_000_000,
134 max_string_length: 10 * 1024 * 1024, }
136 }
137}
138
139impl Default for BufferLimits {
140 fn default() -> Self {
141 Self {
142 max_buffer_size: 256 * 1024 * 1024, max_pool_size: 1000,
144 max_total_memory: 512 * 1024 * 1024, buffer_ttl_secs: 300, max_buffers_per_bucket: 50,
147 }
148 }
149}
150
151impl Default for NetworkLimits {
152 fn default() -> Self {
153 Self {
154 max_websocket_frame_size: 16 * 1024 * 1024, max_concurrent_connections: 10_000,
156 connection_timeout_secs: 30,
157 max_requests_per_second: 100,
158 max_http_payload_size: 50 * 1024 * 1024, rate_limiting: RateLimitingConfig::default(),
160 compression_bomb: CompressionBombConfig::default(),
161 }
162 }
163}
164
165impl Default for RateLimitingConfig {
166 fn default() -> Self {
167 Self {
168 max_requests_per_window: 100,
169 window_duration_secs: 60,
170 max_connections_per_ip: 10,
171 max_messages_per_second: 30,
172 burst_allowance: 5,
173 enabled: true,
174 }
175 }
176}
177
178impl Default for SessionLimits {
179 fn default() -> Self {
180 Self {
181 max_session_id_length: 128,
182 min_session_id_length: 8,
183 max_streams_per_session: 100,
184 session_timeout_secs: 3600, max_session_data_size: 100 * 1024 * 1024, }
187 }
188}
189
190impl SecurityConfig {
191 pub fn high_throughput() -> Self {
193 Self {
194 json: JsonLimits {
195 max_input_size: 500 * 1024 * 1024, max_depth: 128,
197 max_object_keys: 50_000,
198 max_array_length: 5_000_000,
199 max_string_length: 50 * 1024 * 1024, },
201 buffers: BufferLimits {
202 max_buffer_size: 1024 * 1024 * 1024, max_pool_size: 5000,
204 max_total_memory: 2 * 1024 * 1024 * 1024, buffer_ttl_secs: 600, max_buffers_per_bucket: 200,
207 },
208 network: NetworkLimits {
209 max_websocket_frame_size: 100 * 1024 * 1024, max_concurrent_connections: 50_000,
211 connection_timeout_secs: 60,
212 max_requests_per_second: 1000,
213 max_http_payload_size: 200 * 1024 * 1024, rate_limiting: RateLimitingConfig {
215 max_requests_per_window: 1000,
216 window_duration_secs: 60,
217 max_connections_per_ip: 50,
218 max_messages_per_second: 100,
219 burst_allowance: 20,
220 enabled: true,
221 },
222 compression_bomb: CompressionBombConfig::high_throughput(),
223 },
224 sessions: SessionLimits {
225 max_session_id_length: 256,
226 min_session_id_length: 16,
227 max_streams_per_session: 1000,
228 session_timeout_secs: 7200, max_session_data_size: 500 * 1024 * 1024, },
231 }
232 }
233
234 pub fn low_memory() -> Self {
236 Self {
237 json: JsonLimits {
238 max_input_size: 10 * 1024 * 1024, max_depth: 32,
240 max_object_keys: 1_000,
241 max_array_length: 100_000,
242 max_string_length: 1024 * 1024, },
244 buffers: BufferLimits {
245 max_buffer_size: 10 * 1024 * 1024, max_pool_size: 100,
247 max_total_memory: 50 * 1024 * 1024, buffer_ttl_secs: 60, max_buffers_per_bucket: 10,
250 },
251 network: NetworkLimits {
252 max_websocket_frame_size: 1024 * 1024, max_concurrent_connections: 1_000,
254 connection_timeout_secs: 15,
255 max_requests_per_second: 10,
256 max_http_payload_size: 5 * 1024 * 1024, rate_limiting: RateLimitingConfig {
258 max_requests_per_window: 20,
259 window_duration_secs: 60,
260 max_connections_per_ip: 2,
261 max_messages_per_second: 5,
262 burst_allowance: 2,
263 enabled: true,
264 },
265 compression_bomb: CompressionBombConfig::low_memory(),
266 },
267 sessions: SessionLimits {
268 max_session_id_length: 64,
269 min_session_id_length: 8,
270 max_streams_per_session: 10,
271 session_timeout_secs: 900, max_session_data_size: 10 * 1024 * 1024, },
274 }
275 }
276
277 pub fn development() -> Self {
279 Self {
280 json: JsonLimits {
281 max_input_size: 50 * 1024 * 1024, max_depth: 64,
283 max_object_keys: 5_000,
284 max_array_length: 500_000,
285 max_string_length: 5 * 1024 * 1024, },
287 buffers: BufferLimits {
288 max_buffer_size: 100 * 1024 * 1024, max_pool_size: 500,
290 max_total_memory: 200 * 1024 * 1024, buffer_ttl_secs: 120, max_buffers_per_bucket: 25,
293 },
294 network: NetworkLimits {
295 max_websocket_frame_size: 10 * 1024 * 1024, max_concurrent_connections: 1_000,
297 connection_timeout_secs: 30,
298 max_requests_per_second: 50,
299 max_http_payload_size: 25 * 1024 * 1024, rate_limiting: RateLimitingConfig {
301 max_requests_per_window: 200,
302 window_duration_secs: 60,
303 max_connections_per_ip: 20,
304 max_messages_per_second: 50,
305 burst_allowance: 10,
306 enabled: true,
307 },
308 compression_bomb: CompressionBombConfig::default(),
309 },
310 sessions: SessionLimits {
311 max_session_id_length: 128,
312 min_session_id_length: 8,
313 max_streams_per_session: 50,
314 session_timeout_secs: 1800, max_session_data_size: 50 * 1024 * 1024, },
317 }
318 }
319
320 pub fn buffer_ttl(&self) -> Duration {
322 Duration::from_secs(self.buffers.buffer_ttl_secs)
323 }
324
325 pub fn connection_timeout(&self) -> Duration {
327 Duration::from_secs(self.network.connection_timeout_secs)
328 }
329
330 pub fn session_timeout(&self) -> Duration {
332 Duration::from_secs(self.sessions.session_timeout_secs)
333 }
334}
335
336#[cfg(test)]
337mod tests {
338 use super::*;
339
340 #[test]
341 fn test_default_security_config() {
342 let config = SecurityConfig::default();
343
344 assert!(config.json.max_input_size > 0);
346 assert!(config.buffers.max_buffer_size > 0);
347 assert!(config.network.max_concurrent_connections > 0);
348 assert!(config.sessions.max_session_id_length >= config.sessions.min_session_id_length);
349 }
350
351 #[test]
352 fn test_high_throughput_config() {
353 let config = SecurityConfig::high_throughput();
354 let default = SecurityConfig::default();
355
356 assert!(config.json.max_input_size >= default.json.max_input_size);
358 assert!(config.buffers.max_total_memory >= default.buffers.max_total_memory);
359 assert!(
360 config.network.max_concurrent_connections >= default.network.max_concurrent_connections
361 );
362 }
363
364 #[test]
365 fn test_low_memory_config() {
366 let config = SecurityConfig::low_memory();
367 let default = SecurityConfig::default();
368
369 assert!(config.json.max_input_size <= default.json.max_input_size);
371 assert!(config.buffers.max_total_memory <= default.buffers.max_total_memory);
372 assert!(config.buffers.max_buffers_per_bucket <= default.buffers.max_buffers_per_bucket);
373 }
374
375 #[test]
376 fn test_duration_conversions() {
377 let config = SecurityConfig::default();
378
379 assert!(config.buffer_ttl().as_secs() > 0);
380 assert!(config.connection_timeout().as_secs() > 0);
381 assert!(config.session_timeout().as_secs() > 0);
382 }
383}