Shield
Shield is a security middleware package for Nimbus that protects web applications from common web attacks. It sets secure HTTP headers, provides CSRF protection, and includes a Content Security Policy builder — all in a single, composable package.
Installation
Shield ships with Nimbus under packages/shield. Import it directly:
import "github.com/CodeSyncr/nimbus/packages/shield"
Quick Start
Register Shield in start/kernel.go alongside your other middleware:
package start
import (
"github.com/CodeSyncr/nimbus"
"github.com/CodeSyncr/nimbus/middleware"
"github.com/CodeSyncr/nimbus/packages/shield"
)
func RegisterMiddleware(app *nimbus.App) {
cfg := shield.DefaultConfig()
app.Router.Use(
middleware.Logger(),
middleware.Recover(),
shield.Guard(cfg),
shield.CSRFGuard(cfg.CSRF),
)
}
Security Headers
shield.Guard(cfg) sets the following headers on every response. Each can be
individually configured or disabled.
| Header | Default Value | Purpose |
|---|---|---|
X-Content-Type-Options |
nosniff |
Prevents MIME-type sniffing |
X-XSS-Protection |
0 |
Disables legacy XSS auditor (use CSP instead) |
X-Frame-Options |
SAMEORIGIN |
Clickjacking protection |
Referrer-Policy |
strict-origin-when-cross-origin |
Controls referrer information |
X-DNS-Prefetch-Control |
off |
Controls browser DNS prefetching |
X-Download-Options |
noopen |
Prevents old IE from executing downloads |
X-Permitted-Cross-Domain-Policies |
none |
Restricts Flash/PDF cross-domain access |
Cross-Origin-Opener-Policy |
same-origin |
Isolates browsing context |
Cross-Origin-Resource-Policy |
same-origin |
Controls resource loading across origins |
Strict-Transport-Security |
disabled | Forces HTTPS (enable for production) |
Configuration
Override any default by modifying the Config struct:
cfg := shield.DefaultConfig()
// Clickjacking: deny all framing
cfg.FrameGuard = "DENY"
// Enable HSTS for production
cfg.HSTS.Enabled = true
cfg.HSTS.MaxAge = 365 * 24 * time.Hour
cfg.HSTS.IncludeSubdomains = true
cfg.HSTS.Preload = true
// Disable CSRF for an API-only app
cfg.CSRF.Enabled = false
app.Router.Use(shield.Guard(cfg))
CSRF Protection
Shield uses a signed double-submit cookie pattern. On every request a cryptographically random token is generated, HMAC-signed, and stored in a cookie. Unsafe methods (POST, PUT, PATCH, DELETE) must include the raw token in a header or form field.
How it works
- Middleware generates a 256-bit random token and sets it as a signed cookie.
- The raw token is stored in the request context.
- Templates use
{{ .csrfField }}— auto-injected byctx.Viewwhen Shield CSRF is enabled. - On form submit, the token is sent as a hidden field (
_csrf) or header (X-CSRF-Token). - Middleware validates the submitted token against the cookie, using constant-time comparison.
- Tokens rotate after each successful validation (one-time use).
Template usage
Include {{ .csrfField }} in every form. It renders a hidden input with the token.
<form method="POST" action="/posts">
{{ .csrfField }}
<input type="text" name="title">
<button type="submit">Create</button>
</form>
JavaScript / AJAX usage
If HttpOnly is false, client-side JS can read the cookie and send
the token in a custom header:
cfg.CSRF.HttpOnly = false
// In your JavaScript:
const token = document.cookie
.split('; ')
.find(c => c.startsWith('__nimbus_csrf='))
?.split('=')[1]
?.split('.')[0] // raw token before signature
fetch('/api/posts', {
method: 'POST',
headers: { 'X-CSRF-Token': token },
body: JSON.stringify({ title: 'Hello' })
})
Excepting paths
Skip CSRF validation for API routes or webhooks:
cfg.CSRF.ExceptPaths = []string{
"/api/",
"/webhooks/",
}
Custom error handler
cfg.CSRF.ErrorHandler = func(c *http.Context) error {
return c.JSON(http.StatusForbidden, map[string]string{
"error": "csrf_mismatch",
"message": "Your session has expired. Please refresh the page.",
})
}
Content Security Policy
Shield includes a fluent CSP builder. Use the presets or build your own policy directive by directive.
Strict preset
cfg.CSP = shield.CSPConfig{
Enabled: true,
Policy: shield.Strict(),
}
// default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; ...
Relaxed preset
cfg.CSP = shield.CSPConfig{
Enabled: true,
Policy: shield.Relaxed(),
}
// Allows CDN assets, inline styles — good for development
Custom policy
cfg.CSP = shield.CSPConfig{
Enabled: true,
Policy: shield.NewCSP().
DefaultSrc("'self'").
ScriptSrc("'self'", "https://cdn.jsdelivr.net").
StyleSrc("'self'", "'unsafe-inline'", "https://fonts.googleapis.com").
FontSrc("'self'", "https://fonts.gstatic.com").
ImgSrc("'self'", "data:", "https:").
ConnectSrc("'self'", "wss:").
ObjectSrc("'none'").
FrameAncestors("'none'").
BaseURI("'self'").
FormAction("'self'"),
}
Nonce-based scripts
policy := shield.NewCSP().DefaultSrc("'self'")
nonce := policy.Nonce("script-src")
// In template: <script nonce="{{ nonce }}">...</script>
Report-only mode
Test a policy without enforcing it:
cfg.CSP = shield.CSPConfig{
Enabled: true,
ReportOnly: true,
Policy: shield.Strict().ReportURI("/csp-violations"),
}
Additional Middleware
Origin verification
Validate the Origin / Referer header on unsafe requests:
app.Router.Use(shield.VerifyOrigin("example.com", "www.example.com"))
Remove sensitive headers
app.Router.Use(shield.RemoveHeader("X-Powered-By", "Server"))
Timing-safe responses
Pad response times to a fixed duration to mitigate timing side-channels on sensitive endpoints:
app.Router.Post("/login", loginHandler, shield.NoTimingLeak(500*time.Millisecond))
Plugin Mode
Instead of registering middleware manually, you can use Shield as a Nimbus plugin in
bin/server.go. This exposes named middleware "shield" and
"csrf" that you can attach to routes or groups.
import "github.com/CodeSyncr/nimbus/packages/shield"
app.Use(shield.NewPlugin(shield.DefaultConfig()))
Full Example
package start
import (
"time"
"github.com/CodeSyncr/nimbus"
"github.com/CodeSyncr/nimbus/middleware"
"github.com/CodeSyncr/nimbus/packages/shield"
)
func RegisterMiddleware(app *nimbus.App) {
cfg := shield.DefaultConfig()
// Production hardening
cfg.HSTS.Enabled = true
cfg.HSTS.MaxAge = 365 * 24 * time.Hour
cfg.HSTS.Preload = true
cfg.CSRF.Secure = true
// CSP
cfg.CSP = shield.CSPConfig{
Enabled: true,
Policy: shield.NewCSP().
DefaultSrc("'self'").
ScriptSrc("'self'", "https://cdn.jsdelivr.net").
StyleSrc("'self'", "'unsafe-inline'").
ImgSrc("'self'", "data:").
ObjectSrc("'none'").
FrameAncestors("'none'"),
}
// Skip CSRF for API routes
cfg.CSRF.ExceptPaths = []string{"/api/"}
app.Router.Use(
middleware.Logger(),
middleware.Recover(),
shield.Guard(cfg),
shield.CSRFGuard(cfg.CSRF),
shield.RemoveHeader("X-Powered-By"),
)
}