diff options
| author | Rose Hogenson <rosehogenson@posteo.net> | 2025-10-14 11:46:56 -0700 |
|---|---|---|
| committer | Rose Hogenson <rosehogenson@posteo.net> | 2025-10-14 11:46:56 -0700 |
| commit | 21d7462b057838eb173145d79d2b9fd6c71e8053 (patch) | |
| tree | 906573ab446f6f62fa24c566529e3e415a3b746c | |
| parent | f475bf0e8a0e2b59fbc8f300c882e30c04c972f5 (diff) | |
| download | roseh.moe-21d7462b057838eb173145d79d2b9fd6c71e8053.tar.zst | |
Remove CSRF tokens
I think the built-in cross-origin protection will be good enough.
| -rw-r--r-- | roseh.moe.go | 108 | ||||
| -rw-r--r-- | templates/login.html.template | 1 | ||||
| -rw-r--r-- | templates/note.html.template | 1 |
3 files changed, 32 insertions, 78 deletions
diff --git a/roseh.moe.go b/roseh.moe.go index 481da6b..1783a03 100644 --- a/roseh.moe.go +++ b/roseh.moe.go @@ -371,63 +371,31 @@ func attachCookie(w http.ResponseWriter) error { return nil } -func cookieAuth(w http.ResponseWriter, r *http.Request) (string, bool) { - const csrfTokenLen = 32 - var csrfToken string - if csrfCookie, err := r.Cookie("csrf-token"); err == nil { - csrfToken = csrfCookie.Value - } else { - buf := make([]byte, csrfTokenLen) - rand.Read(buf) - csrfToken = base64.RawURLEncoding.EncodeToString(buf) - http.SetCookie(w, &http.Cookie{ - Name: "csrf-token", - Value: csrfToken, - Path: "/", - Secure: true, - HttpOnly: true, - SameSite: http.SameSiteStrictMode, - Partitioned: true, - }) - } - +func cookieAuth(w http.ResponseWriter, r *http.Request) bool { cookie, err := r.Cookie("auth") if err != nil { - return csrfToken, false + return false } authCookie, err := base64.RawURLEncoding.DecodeString(cookie.Value) if err != nil { - return csrfToken, false + return false } msg, ok := verify(authCookie) if !ok { - return csrfToken, false + return false } var t time.Time if err := t.UnmarshalBinary(msg); err != nil { - return csrfToken, false + return false } cookieAge := time.Since(t) if cookieAge > cookieExpiration { - return csrfToken, false + return false } if cookieAge > 24*time.Hour { attachCookie(w) } - return csrfToken, true -} - -func checkCSRFToken(r *http.Request) error { - cookie, err := r.Cookie("csrf-token") - if err != nil { - return err - } - cookieHash := sha256.Sum256([]byte(cookie.Value)) - formValueHash := sha256.Sum256([]byte(r.FormValue("csrf-token"))) - if subtle.ConstantTimeCompare(cookieHash[:], formValueHash[:]) == 0 { - return fmt.Errorf("bad CSRF token") - } - return nil + return true } func checkPassword(password string) bool { @@ -443,26 +411,18 @@ var ( ) type loginTemplateArgs struct { - CSRFToken string - Error bool + Error bool } -func executeLoginTemplate(w io.Writer, csrfToken string) { - if err := loginTemplate.Execute(w, loginTemplateArgs{CSRFToken: csrfToken}); err != nil { +func executeLoginTemplate(w io.Writer) { + if err := loginTemplate.Execute(w, loginTemplateArgs{}); err != nil { log.Printf("Warning: login: %s", err) } } func login(w http.ResponseWriter, r *http.Request) { - if err := checkCSRFToken(r); err != nil { - http.Error(w, "bad CSRF token", http.StatusBadRequest) - return - } if !checkPassword(r.FormValue("password")) { - if err := loginTemplate.Execute(w, loginTemplateArgs{ - Error: true, - CSRFToken: r.FormValue("csrf-token"), - }); err != nil { + if err := loginTemplate.Execute(w, loginTemplateArgs{Error: true}); err != nil { log.Printf("Warning: login: %s", err) } return @@ -481,29 +441,24 @@ var ( ) type notepadTemplateArgs struct { - Content string - CSRFToken string + Content string } func notepad(w http.ResponseWriter, r *http.Request) { - csrfToken, ok := cookieAuth(w, r) - if !ok { - executeLoginTemplate(w, csrfToken) + if !cookieAuth(w, r) { + executeLoginTemplate(w) return } notepadContentsMu.Lock() currentContent := notepadContents notepadContentsMu.Unlock() - if err := notepadTemplate.Execute(w, notepadTemplateArgs{Content: currentContent, CSRFToken: csrfToken}); err != nil { + if err := notepadTemplate.Execute(w, notepadTemplateArgs{Content: currentContent}); err != nil { log.Printf("Warning: notepad: %s", err) } } func saveNote(w http.ResponseWriter, r *http.Request) error { - if err := checkCSRFToken(r); err != nil { - return err - } - if _, ok := cookieAuth(w, r); !ok { + if !cookieAuth(w, r) { return fmt.Errorf("not logged in") } newContent := r.FormValue("content") @@ -566,22 +521,23 @@ func main() { log.Fatal(err) } - http.HandleFunc("GET /pong", pong) - http.HandleFunc("GET /wormhole", wormhole) - http.HandleFunc("POST /wormhole/{hole}", wormholeSend) - http.HandleFunc("GET /wormhole/{hole}", wormholeRecv) - http.HandleFunc("GET /wormhole/{hole}/ready", wormholeReady) - http.HandleFunc("POST /login", login) - http.HandleFunc("GET /notepad", notepad) - http.HandleFunc("POST /notepad", autosave) - http.HandleFunc("GET /cmd/{cmd}", cmd) - http.HandleFunc("GET /pkg/{pkg}", pkg) - http.HandleFunc("GET /static/", static) - http.HandleFunc("GET /favicon.ico", favicon) - http.HandleFunc("GET /{$}", index) - http.HandleFunc("GET /", notFound) + mux := http.NewServeMux() + mux.HandleFunc("GET /pong", pong) + mux.HandleFunc("GET /wormhole", wormhole) + mux.HandleFunc("POST /wormhole/{hole}", wormholeSend) + mux.HandleFunc("GET /wormhole/{hole}", wormholeRecv) + mux.HandleFunc("GET /wormhole/{hole}/ready", wormholeReady) + mux.HandleFunc("POST /login", login) + mux.HandleFunc("GET /notepad", notepad) + mux.HandleFunc("POST /notepad", autosave) + mux.HandleFunc("GET /cmd/{cmd}", cmd) + mux.HandleFunc("GET /pkg/{pkg}", pkg) + mux.HandleFunc("GET /static/", static) + mux.HandleFunc("GET /favicon.ico", favicon) + mux.HandleFunc("GET /{$}", index) + mux.HandleFunc("GET /", notFound) addr := fmt.Sprintf(":%d", *port) log.Printf("Listening on %q", addr) - log.Fatal(http.ListenAndServe(addr, nil)) + log.Fatal(http.ListenAndServe(addr, http.NewCrossOriginProtection().Handler(mux))) } diff --git a/templates/login.html.template b/templates/login.html.template index f08caf7..0cf3469 100644 --- a/templates/login.html.template +++ b/templates/login.html.template @@ -5,7 +5,6 @@ <p class="login-error">Incorrect password</p> {{end}} <form class="password-form" action="/login" method="post"> - <input type="hidden" name="csrf-token" value="{{.CSRFToken}}"> <label class="password-label" for="password">Enter password</label> <input id="password" class="password" type="password" name="password" autofocus> </form> diff --git a/templates/note.html.template b/templates/note.html.template index 07c2d8e..19da416 100644 --- a/templates/note.html.template +++ b/templates/note.html.template @@ -6,7 +6,6 @@ {{end}} <form id="form" method="post"> - <input type="hidden" name="csrf-token" value="{{.CSRFToken}}"> <div class="save-indicator-container"> {{block "saveIndicator" ""}} <span id="save-indicator">{{.}}</span> |
