-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpresets.go
More file actions
450 lines (382 loc) · 14.2 KB
/
Copy pathpresets.go
File metadata and controls
450 lines (382 loc) · 14.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
package servex
import (
"crypto/tls"
"time"
)
// MergeWithPreset merges a preset with additional options.
func MergeWithPreset(preset []Option, opts ...Option) []Option {
return append(preset, opts...)
}
// MergePresets merges multiple presets into a single slice of options.
func MergePresets(presets ...[]Option) []Option {
var opts []Option
for _, preset := range presets {
opts = append(opts, preset...)
}
return opts
}
// PresetOptions provides common server configurations for different use cases.
// These presets combine multiple options to create ready-to-use server setups.
// DevelopmentPreset returns options suitable for development environment.
// Features: basic logging, no security restrictions, no rate limiting, detailed error reporting.
func DevelopmentPreset() []Option {
return []Option{
WithHealthEndpoint(),
WithDefaultMetrics(), // Enable metrics for development monitoring
WithDebug(), // Enable debug mode: send errors to client, verbose logging
}
}
// ProductionPreset returns options suitable for production environment.
// Features: security headers, CSRF protection, rate limiting, request logging, health endpoints, metrics, compression.
// TLS certificate is optional — omit it when running behind a reverse proxy (nginx, Cloudflare, AWS ALB).
func ProductionPreset(cert ...tls.Certificate) []Option {
opts := []Option{
WithReadTimeout(10 * time.Second),
WithReadHeaderTimeout(5 * time.Second),
WithIdleTimeout(120 * time.Second),
// Security with CSRF protection
WithStrictSecurityHeaders(),
WithCSRFProtection(),
WithRemoveHeaders("Server", "X-Powered-By"),
// Request size limits for production security
WithRequestSizeLimits(),
// Rate limiting - conservative defaults
WithRPS(100), // 100 requests per second
// Compression for bandwidth optimization
WithCompression(),
WithCompressionLevel(6), // Balanced compression
// Health and monitoring
WithHealthEndpoint(),
WithDefaultMetrics(),
// Audit logging for security events
WithDefaultAuditLogger(),
// Security exclusions for monitoring
WithSecurityExcludePaths("/health", "/metrics", "/.well-known/"),
WithRateLimitExcludePaths("/health", "/metrics"),
WithCompressionExcludePaths("/metrics"), // Exclude metrics from compression for clarity
}
if len(cert) > 0 {
opts = append(opts,
WithCertificate(cert[0]),
WithHTTPSRedirect(),
)
}
return opts
}
// APIServerPreset returns options for a typical REST API server.
// Features: security headers, CORS, API rate limiting, request size limits, compression, caching.
func APIServerPreset() []Option {
return []Option{
WithReadTimeout(15 * time.Second),
WithIdleTimeout(90 * time.Second),
// Security headers with API-friendly settings
WithSecurityHeaders(),
WithContentSecurityPolicy("default-src 'none'"), // APIs don't need CSP typically
// CORS with permissive defaults for API usage
WithCORS(),
// Request size limits appropriate for APIs
WithMaxRequestBodySize(10 << 20), // 10 MB
WithMaxJSONBodySize(1 << 20), // 1 MB
WithEnableRequestSizeLimits(true),
// Rate limiting suitable for APIs
WithRPM(1000), // 1000 requests per minute per client
WithBurstSize(50),
// Compression for API responses
WithCompression(),
WithCompressionLevel(4), // Fast compression for APIs
// Cache control for API responses
WithCacheAPI(300), // 5 minutes cache for stable API responses
// Health endpoints
WithHealthEndpoint(),
WithDefaultMetrics(),
// Audit logging for API security events
WithDefaultAuditLogger(),
// Exclude health from security restrictions
WithSecurityExcludePaths("/health", "/metrics"),
WithRateLimitExcludePaths("/health", "/metrics"),
WithCompressionExcludePaths("/metrics"), // Keep metrics uncompressed
}
}
// WebAppPreset returns options for serving web applications.
// Features: web security headers, CSRF protection, content protection, static file friendly, size limits, compression.
// TLS certificate is optional — omit it when running behind a reverse proxy (nginx, Cloudflare, AWS ALB).
func WebAppPreset(cert ...tls.Certificate) []Option {
opts := []Option{
WithReadTimeout(30 * time.Second),
WithIdleTimeout(180 * time.Second),
// Web security headers with CSRF protection
WithStrictSecurityHeaders(),
WithCSRFProtection(),
WithCSRFTokenEndpoint("/csrf-token"), // Enable token endpoint for SPAs
WithContentSecurityPolicy(
"default-src 'self'; " +
"script-src 'self' 'unsafe-inline'; " +
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; " +
"font-src 'self' https://fonts.gstatic.com; " +
"img-src 'self' data: https:; " +
"connect-src 'self'",
),
WithRemoveHeaders("Server", "X-Powered-By"),
// Request size limits for web applications
WithMaxRequestBodySize(50 << 20), // 50 MB for file uploads
WithMaxJSONBodySize(5 << 20), // 5 MB for JSON
WithEnableRequestSizeLimits(true),
// Rate limiting for web apps
WithRPS(50), // 50 requests per second per user
// Compression for web assets and API responses
WithCompression(),
WithCompressionLevel(6), // Balanced compression for web content
// Health endpoint
WithHealthEndpoint(),
WithDefaultMetrics(),
// Exclude common web assets from restrictions
WithSecurityExcludePaths("/health", "/favicon.ico", "/robots.txt", "/.well-known/", "/csrf-token", "/metrics"),
WithRateLimitExcludePaths("/health", "/favicon.ico", "/robots.txt", "/static/", "/csrf-token", "/metrics"),
WithCompressionExcludePaths("/metrics"), // Keep metrics uncompressed for monitoring tools
}
if len(cert) > 0 {
opts = append(opts,
WithCertificate(cert[0]),
WithHTTPSRedirect(),
)
}
return opts
}
// MicroservicePreset returns options for microservice environments.
// Features: minimal security (behind gateway), fast timeouts, health checks, size limits.
func MicroservicePreset() []Option {
return []Option{
WithReadTimeout(5 * time.Second),
WithReadHeaderTimeout(2 * time.Second),
WithIdleTimeout(30 * time.Second),
// Minimal security (assuming behind API gateway)
WithSecurityHeaders(), // Basic headers only
// Request size limits for microservices
WithMaxRequestBodySize(5 << 20), // 5 MB
WithMaxJSONBodySize(1 << 20), // 1 MB
WithEnableRequestSizeLimits(true),
// Conservative rate limiting (assuming gateway handles this)
WithRPS(200),
// Health and monitoring
WithHealthEndpoint(),
WithDefaultMetrics(),
// Exclude monitoring from restrictions
WithSecurityExcludePaths("/health", "/metrics"),
WithRateLimitExcludePaths("/health", "/metrics"),
}
}
// HighSecurityPreset returns options for high-security applications.
// Features: strict security headers, CSRF protection, request filtering, comprehensive rate limiting, audit logging.
// TLS certificate is optional — omit it when running behind a reverse proxy (nginx, Cloudflare, AWS ALB).
func HighSecurityPreset(cert ...tls.Certificate) []Option {
opts := []Option{
WithReadTimeout(10 * time.Second),
WithReadHeaderTimeout(3 * time.Second),
WithIdleTimeout(60 * time.Second),
// Strict security with CSRF protection
WithStrictSecurityHeaders(),
WithCSRFProtection(),
WithCSRFCookieHttpOnly(true), // Maximum security for CSRF cookies
WithCSRFCookieSameSite("Strict"), // Strictest SameSite policy
WithRemoveHeaders("Server", "X-Powered-By"),
// Strict request size limits
WithStrictRequestSizeLimits(), // Smaller limits for high security
// Request filtering
WithBlockedUserAgentsRegex(
".*[Bb]ot.*", // Block bots
".*[Ss]craper.*", // Block scrapers
),
WithBlockedQueryParams(map[string][]string{
"debug": {"true", "1", "on"},
"test": {"true", "1", "on"},
"admin": {"true", "1", "on"},
}),
// Aggressive rate limiting
WithRPS(20), // 20 requests per second
WithBurstSize(5),
// Comprehensive audit logging for security events
WithDefaultAuditLogger(),
WithAuditLogHeaders(true), // Include headers in audit logs
// Health endpoint only
WithHealthEndpoint(),
WithSecurityExcludePaths("/health"),
WithRateLimitExcludePaths("/health"),
WithFilterExcludePaths("/health"),
}
if len(cert) > 0 {
opts = append(opts,
WithCertificate(cert[0]),
WithHTTPSRedirect(),
)
}
return opts
}
// TLSPreset returns options for quick SSL/TLS setup.
// Provide cert object or cert and key files.
func TLSPreset(certFile, keyFile string, cert ...tls.Certificate) []Option {
options := []Option{
WithHTTPSRedirect(),
WithHSTSHeader(31536000, true, true), // 1 year HSTS with preload
}
if len(cert) > 0 {
options = append(options, WithCertificate(cert[0]))
}
if certFile != "" && keyFile != "" {
options = append(options, WithCertificateFromFile(certFile, keyFile))
}
return options
}
// SPAPreset returns options for serving a Single Page Application (React, Vue, Angular).
// Features: SPA mode with index.html fallback, compression, static asset caching, security headers, rate limiting.
// TLS certificate is optional — omit it when running behind a reverse proxy.
//
// Example:
//
// // Serve React build directory
// server, _ := servex.NewServer(servex.SPAPreset("build")...)
//
// // With TLS
// server, _ := servex.NewServer(servex.SPAPreset("dist", cert)...)
//
// // With custom options
// server, _ := servex.NewServer(servex.MergeWithPreset(
// servex.SPAPreset("build"),
// servex.WithCORSAllowOrigins("https://myapp.com"),
// )...)
func SPAPreset(dir string, cert ...tls.Certificate) []Option {
opts := []Option{
WithReadTimeout(30 * time.Second),
WithIdleTimeout(180 * time.Second),
// SPA mode: serve static files with index.html fallback for client-side routing
WithSPAMode(dir, "index.html"),
// Compression for web assets
WithCompression(),
WithCompressionLevel(6),
// Long cache for static assets (hashed filenames)
WithCacheStaticAssets(31536000), // 1 year
// Basic security headers
WithSecurityHeaders(),
// Rate limiting
WithRPS(50),
// Health and monitoring
WithHealthEndpoint(),
WithDefaultMetrics(),
// Exclude paths from restrictions
WithRateLimitExcludePaths("/health", "/metrics"),
WithSecurityExcludePaths("/health", "/metrics"),
WithCompressionExcludePaths("/metrics"),
}
if len(cert) > 0 {
opts = append(opts,
WithCertificate(cert[0]),
WithHTTPSRedirect(),
WithHSTSHeader(31536000, true, true),
)
}
return opts
}
// AuthAPIPreset returns options for a quick-start authenticated REST API.
// Features: everything from APIServerPreset plus in-memory auth database for rapid prototyping.
//
// This preset is designed for development and prototyping. For production, use APIServerPreset
// with WithAuth(db) and WithAuthKey() to provide your own database and signing keys.
//
// Example:
//
// // Quick authenticated API for prototyping
// server, _ := servex.NewServer(servex.AuthAPIPreset()...)
//
// // With custom options
// server, _ := servex.NewServer(servex.MergeWithPreset(
// servex.AuthAPIPreset(),
// servex.WithAuthInitialUsers(servex.InitialUser{
// Username: "admin", Password: "admin123",
// Roles: []servex.UserRole{"admin"},
// }),
// )...)
func AuthAPIPreset() []Option {
return append(APIServerPreset(),
WithAuthMemoryDatabase(),
)
}
// StaticFilePreset returns options for serving static files from a directory.
// Features: static file serving, compression, asset caching, security headers, health endpoint.
//
// Example:
//
// // Serve files from "public/" at "/static" path
// server, _ := servex.NewServer(servex.StaticFilePreset("public", "/static")...)
//
// // Serve files from "assets/" at root
// server, _ := servex.NewServer(servex.StaticFilePreset("assets", "")...)
func StaticFilePreset(dir, prefix string) []Option {
return []Option{
// Serve static files from directory at URL prefix
WithStaticFiles(dir, prefix),
// Compression for static assets
WithCompression(),
WithCompressionLevel(6),
// Long cache for static assets
WithCacheStaticAssets(31536000), // 1 year
// Basic security headers
WithSecurityHeaders(),
// Health and monitoring
WithHealthEndpoint(),
WithDefaultMetrics(),
// Exclude paths from restrictions
WithSecurityExcludePaths("/health", "/metrics"),
WithCompressionExcludePaths("/metrics"),
}
}
// ScannerBlockPreset returns options that block common vulnerability scanners and probes.
// This blocks dotfile access, WordPress probes, actuator endpoints, PHP/Java/ASP attack paths,
// and known scanner User-Agents. Returns 404 with empty body to avoid revealing that filtering is active.
//
// Combine with other presets for production use:
//
// server, _ := servex.NewServer(servex.MergePresets(
// servex.ProductionPreset(),
// servex.ScannerBlockPreset(),
// )...)
//
// If your application legitimately uses any of the blocked paths (e.g., /debug or /swagger),
// remove them from the preset or add them to WithFilterExcludePaths().
func ScannerBlockPreset() []Option {
return []Option{
WithBlockedPathPrefixes(
"/.", // dotfiles (.env, .git, .htaccess, .DS_Store, etc.)
"/_all_dbs", // CouchDB enumeration
"/actuator", // Spring Boot actuator
"/api-docs", // Swagger/OpenAPI probes
"/cgi-bin", // CGI probes
"/debug", // Debug endpoints
"/ecp", // Microsoft Exchange probes
"/elmah", // .NET error log viewer
"/info.php", // PHP info disclosure
"/login.action", // Apache Struts
"/owa", // Outlook Web Access
"/server-status", // Apache server-status
"/telescope", // Laravel Telescope
"/v2/api-docs", // Swagger v2
"/v3/api-docs", // Swagger v3
"/webjars", // WebJars
"/wp-", // WordPress (wp-admin, wp-login, wp-content, etc.)
"/xmlrpc.php", // WordPress XML-RPC
"/admin/config", // Admin config probes
),
WithBlockedPathPatterns(
`(?i)/phpmyadmin`, // phpMyAdmin (any case)
),
WithBlockedUserAgentsRegex(
"(?i)nikto", // Nikto scanner
"(?i)sqlmap", // SQLMap
"(?i)nmap", // Nmap scripting engine
"(?i)masscan", // Masscan
"(?i)zgrab", // ZGrab
"(?i)gobuster", // Gobuster
"(?i)dirbuster", // DirBuster
),
WithFilterStatusCode(404), // Return 404, not 403 — don't reveal filtering
WithFilterMessage(""), // Empty response body
}
}