feat(honeybar): HoneyOS-Leiste einbinden, CSP-Ausnahme dafür
Die Leiste kommt als Skript von der HoneyOS-Domain und holt sich von dort ihre App-Liste. Beides blockte die CSP bisher (script-src / connect-src fielen auf 'self' zurueck) – ohne Ausnahme erschien sie gar nicht. - HONEYBAR_ORIGIN nimmt genau diesen einen Ursprung in script-src und connect-src auf. Leer heisst: keine Leiste, und die Regel bleibt so eng wie bisher. Frame-Freigabe erbt sie ausdruecklich nicht. - SecurityHeaders nimmt die Ausnahmen jetzt als CSP-Struct statt als variadische frameSrc-Liste – mit drei Richtungen wurde das sonst unklar. - Das <script>-Tag steht in der index.html und nicht serverseitig eingespritzt: der Service Worker legt die index.html in seinen Vorrat (navigateFallback), was zur Bauzeit fehlt, kaeme im Browser nie an. - defer, damit ein langsames oder abgeschaltetes HoneyOS den Start von Aether nicht ausbremst. Tests fuer die neue Regel: eng ohne Ausnahme, beide Richtungen mit, Pfad wird auf den Ursprung gekuerzt, Adresse ohne Schema faellt raus. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b5a83e4057
commit
9b8e82cdb2
6 files changed
+164
-17
No files matched your search
@@ -6,26 +6,52 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CSP nennt die Ursprünge, die zusätzlich zu 'self' erlaubt sind.
|
||||
//
|
||||
// Jedes Feld ist eine bewusst enge Ausnahme mit einem konkreten Anlass. Leer
|
||||
// heißt: keine Ausnahme — dann gilt für diese Richtung allein 'self'.
|
||||
type CSP struct {
|
||||
// FrameSrc: Seiten, die in einem <iframe> erscheinen dürfen.
|
||||
// Gebraucht für den Office-Server; `default-src 'self'` deckt auch
|
||||
// `frame-src` ab, ohne Ausnahme blockt der Browser ihn also, noch bevor
|
||||
// eine Anfrage hinausgeht. Gemessen als „Framing 'http://…:9980/'
|
||||
// violates … default-src 'self'".
|
||||
FrameSrc []string
|
||||
|
||||
// ScriptSrc: fremde Ursprünge, von denen Skripte geladen werden dürfen.
|
||||
// ConnectSrc: fremde Ursprünge, die per fetch/XHR erreichbar sein sollen.
|
||||
// Beide gebraucht für eine eingebettete Leiste, die von woanders kommt und
|
||||
// sich ihre Daten selbst holt — das Skript über das eine, die Anfrage über
|
||||
// das andere. Nur eines von beiden zu setzen ergibt selten Sinn.
|
||||
ScriptSrc []string
|
||||
ConnectSrc []string
|
||||
}
|
||||
|
||||
// SecurityHeaders adds security headers that the app controls.
|
||||
// HSTS is intentionally omitted — it belongs on the edge reverse proxy.
|
||||
//
|
||||
// frameSrc nennt zusätzliche Ursprünge, die in einem Rahmen erscheinen dürfen.
|
||||
// Gebraucht für den Office-Server: Seine Bedienoberfläche läuft in einem
|
||||
// <iframe>, und `default-src 'self'` deckt auch `frame-src` ab – ohne
|
||||
// Ausnahme blockt der Browser sie, noch bevor eine Anfrage hinausgeht.
|
||||
// Gemessen als „Framing 'http://…:9980/' violates … default-src 'self'".
|
||||
//
|
||||
// Bewusst **nur der eine konfigurierte Ursprung** und kein Platzhalter: Die
|
||||
// Ausnahme soll so schmal sein wie der Anlass.
|
||||
func SecurityHeaders(frameSrc ...string) func(http.Handler) http.Handler {
|
||||
frame := "frame-src 'self'"
|
||||
for _, raw := range frameSrc {
|
||||
if origin := originOf(raw); origin != "" {
|
||||
frame += " " + origin
|
||||
// Ausnahmen werden **einzeln benannt** und nie als Platzhalter aufgenommen:
|
||||
// Sie sollen so schmal sein wie ihr Anlass. Ein Eintrag, der sich nicht als
|
||||
// Adresse lesen lässt, wird verworfen statt durchgereicht.
|
||||
func SecurityHeaders(csp CSP) func(http.Handler) http.Handler {
|
||||
directive := func(name string, extra []string) string {
|
||||
out := name + " 'self'"
|
||||
for _, raw := range extra {
|
||||
if origin := originOf(raw); origin != "" {
|
||||
out += " " + origin
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
csp := "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; " +
|
||||
"img-src 'self' data: blob:; " + frame
|
||||
|
||||
policy := strings.Join([]string{
|
||||
"default-src 'self'",
|
||||
directive("script-src", csp.ScriptSrc),
|
||||
"style-src 'self' 'unsafe-inline'",
|
||||
"img-src 'self' data: blob:",
|
||||
directive("connect-src", csp.ConnectSrc),
|
||||
directive("frame-src", csp.FrameSrc),
|
||||
}, "; ")
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -33,7 +59,7 @@ func SecurityHeaders(frameSrc ...string) func(http.Handler) http.Handler {
|
||||
h.Set("X-Content-Type-Options", "nosniff")
|
||||
h.Set("X-Frame-Options", "DENY")
|
||||
h.Set("Referrer-Policy", "strict-origin-when-cross-origin")
|
||||
h.Set("Content-Security-Policy", csp)
|
||||
h.Set("Content-Security-Policy", policy)
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user