Shield (Security)
Harpia comes with a built-in security middleware called Shield, inspired by Helmet.js. It automatically sets various HTTP headers to protect your application from well-known web vulnerabilities like Cross-Site Scripting (XSS), Clickjacking, and Sniffing attacks.
Usage
To enable Shield, simply call the app.shield() method on your application instance.
import harpia from "@harpiats/core";
const app = harpia();
// Add Shield as a global middleware
app.shield();
app.get("/", (req, res) => {
res.send("This response is secured!");
});
By default, Shield enables a strict set of security headers, including Content-Security-Policy (CSP), Strict-Transport-Security (HSTS), X-Frame-Options, and more.
Configuration
You can customize the headers by passing an options object to app.shield().
If you prefer to define your configuration object separately, you can import the SecurityHeaders type from @harpiats/core to maintain full TypeScript support.
import harpia from "@harpiats/core";
import type { SecurityHeaders } from "@harpiats/core";
const app = harpia();
const shieldConfig: SecurityHeaders = {
trustProxy: true, // Enable if your app is behind a reverse proxy (e.g., Nginx, Cloudflare)
xFrameOptions: { action: "DENY" }, // Overrides the default SAMEORIGIN
contentSecurityPolicy: {
directives: {
"default-src": ["'self'"],
"script-src": ["'self'", "https://trusted-cdn.com"],
}
}
};
app.shield(shieldConfig);
Trusting Proxies
If your application is hosted behind a reverse proxy, the client IP address will often be the proxy’s IP. By setting trustProxy: true, Shield will look for headers like x-forwarded-for or cf-connecting-ip to determine the real client IP.
CSP Nonce Generation
A powerful feature of Shield is its automatic nonce (number used once) generation for Content Security Policy. This allows you to safely execute specific inline scripts and styles without opening up your app to XSS.
To enable it, set useNonce: true:
app.shield({
useNonce: true,
contentSecurityPolicy: {
directives: {
"script-src": ["'self'"],
"style-src": ["'self'"],
}
}
});
When useNonce is enabled, Shield automatically generates a secure, random string for each request and adds it to the script-src and style-src directives.
Retrieving the Nonce
You can retrieve the generated nonce for the current request using app.getNonce(). This is typically used when rendering templates to inject the nonce into your <script> or <style> tags.
app.get("/", async (req, res) => {
const nonce = app.getNonce();
// Pass the nonce to your template engine
await res.render("index", { nonce });
});
In your HTML template:
<script nonce="{{ nonce }}">
console.log("This inline script is allowed to run!");
</script>
Nonce Consumption
A nonce is single-use per request. Calling app.getNonce() retrieves it and immediately deletes it from the store to ensure security. Make sure you only call it once per request when rendering your view.
Template Engine Integration
If you are using Harpia’s built-in Template Engine, you don’t need to manually pass the nonce from your controllers.
When you initialize app.shield(), the generateNonce() plugin is automatically registered in the template engine. You can then use it directly in your views:
<script nonce="{{ generateNonce() }}">
console.log("Secure inline script");
</script>