A Ktor web framework plugin to help configure a Content Security Policy (CSP) header.
implementation("com.chalk:ktor-csp:<version>")
Install the plugin in your application module:
install(CSP) {
defaultConfig { call ->
defaultSrc(none)
imgSrc(self, "https://example.net")
scriptSrc(self, nonce)
// These are all equivalent
fontSrc("https://fonts.google.com")
fontSrc = listOf("https://fonts.google.com")
fontSrc += "https://fonts.google.com"
// For any CSP directives that don't have a helper
directive("some-directive") += listOf("https://example.net")
}
}
get("/some-path") {
val nonce = call.cspNonce
call.respondText("<script nonce=\"$nonce\">...</script>")
}
Disable sending the header for all requests:
install(CSP) {
allRequests = false
defaultConfig { call ->
...
}
}
⚠️ WarningIf you do not disable the header for all requests and combine any of the below methods, you will have multiple Content-Security-Policy headers, they will not overwrite each other.
As per the MDN documentation, having multiple headers is valid but may not be what you expect. Each additional CSP header may only further restrict the capabilities of the page, not expand them.
Surround your routes with a csp
block:
routes {
// Use default config
csp {
get("/has-csp") { ... }
}
// Extend default config with more directives
csp({
scriptSrc("https://example.net")
}) {
get("/has-csp")
}
// Ignore defaults and start from scratch
csp(extendDefault = false, {
scriptSrc("https://example.net")
}) {
get("/has-csp")
}
// Not inside a csp block, will not have the header
get("/no-csp") { ... }
}
get("/some-route") {
// Use default config
call.appendCsp()
// Extend default config with more directives
call.appendCsp {
scriptSrc("https://example.net")
}
// Ignore defaults and start from scratch
call.appendCsp(extendDefault = false) {
scriptSrc("https://example.net")
}
}