Commit a5bb98e5 authored by Simao Gomes Viana's avatar Simao Gomes Viana 🛠
Browse files

Add CSP support

parent 370f9e44
...@@ -79,6 +79,7 @@ type InjectedWriter struct { ...@@ -79,6 +79,7 @@ type InjectedWriter struct {
Logger *zap.Logger Logger *zap.Logger
contentTypeStatus ContentTypeStatus contentTypeStatus ContentTypeStatus
LineHandler LineHandler LineHandler LineHandler
cspNonce string
M *Middleware M *Middleware
} }
...@@ -145,6 +146,7 @@ func (i *InjectedWriter) textToInject() (string, error) { ...@@ -145,6 +146,7 @@ func (i *InjectedWriter) textToInject() (string, error) {
func (i *InjectedWriter) HandleLine(line string) (string, error) { func (i *InjectedWriter) HandleLine(line string) (string, error) {
if strings.Contains(line, i.M.Before) { if strings.Contains(line, i.M.Before) {
textToInject, err := i.textToInject() textToInject, err := i.textToInject()
textToInject = i.HandleCSPForText(textToInject)
if err != nil { if err != nil {
return line, nil return line, nil
} }
...@@ -153,6 +155,29 @@ func (i *InjectedWriter) HandleLine(line string) (string, error) { ...@@ -153,6 +155,29 @@ func (i *InjectedWriter) HandleLine(line string) (string, error) {
return line, nil return line, nil
} }
func (i *InjectedWriter) HandleCSP() error {
csp := i.OriginalWriter.Header().Get("Content-Security-Policy")
if len(csp) != 0 {
var err error
i.cspNonce, err = GenerateRandomStringURLSafe(6)
if err != nil {
return err
}
csp += fmt.Sprintf("; script-src 'nonce-%s'", i.cspNonce)
i.OriginalWriter.Header().Set("Content-Security-Policy", csp)
}
return nil
}
func (i *InjectedWriter) HandleCSPForText(line string) string {
if len(i.cspNonce) == 0 {
// Remove nonce attributes since CSP is not active
return strings.ReplaceAll(line, "nonce=\"{{csp-nonce}}\"", "")
}
return strings.ReplaceAll(line, "{{csp-nonce}}", i.cspNonce)
}
func (i *InjectedWriter) Flush() error { func (i *InjectedWriter) Flush() error {
var err error var err error
finalString := i.RecordedHTML.String() finalString := i.RecordedHTML.String()
...@@ -193,9 +218,17 @@ func CreateInjectedWriter( ...@@ -193,9 +218,17 @@ func CreateInjectedWriter(
// ServeHTTP implements caddyhttp.MiddlewareHandler. // ServeHTTP implements caddyhttp.MiddlewareHandler.
func (m Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { func (m Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
var err error
r.Header.Set("Accept-Encoding", "identity") r.Header.Set("Accept-Encoding", "identity")
injectedWriter := CreateInjectedWriter(w, r, &m) injectedWriter := CreateInjectedWriter(w, r, &m)
err := next.ServeHTTP(injectedWriter, r) err = injectedWriter.HandleCSP()
if err != nil {
// Skip injection to ensure availability
return next.ServeHTTP(w, r)
}
err = next.ServeHTTP(injectedWriter, r)
if err != nil { if err != nil {
return err return err
} }
......
package injection
import (
"crypto/rand"
"encoding/base32"
)
func GenerateRandomBytes(len int) ([]byte, error) {
b := make([]byte, len)
_, err := rand.Read(b)
if err != nil {
return nil, err
}
return b, nil
}
func GenerateRandomStringURLSafe(len int) (string, error) {
b, err := GenerateRandomBytes(len)
return base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(b), err
}
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
} }
http://localhost:2015 { http://localhost:2015 {
header Content-Security-Policy "default-src https:; object-src 'none'"
injection { injection {
content_type .*/html content_type .*/html
inject test/inject.js inject test/inject.js
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment