diff options
author | Brian Picciano <mediocregopher@gmail.com> | 2022-05-24 17:42:00 -0600 |
---|---|---|
committer | Brian Picciano <mediocregopher@gmail.com> | 2022-05-24 17:42:00 -0600 |
commit | 08811a6da78c3f1f973b8f50a337ff4dc4ed9e2c (patch) | |
tree | 3fc8fa9025dbdc8099ea145e232f8b25547204b5 | |
parent | 159638084e167047b86fd65382f50cd099d4eb48 (diff) |
Replace CSRF token checking with Referer checking
-rw-r--r-- | srv/src/http/api.go | 5 | ||||
-rw-r--r-- | srv/src/http/csrf.go | 64 | ||||
-rw-r--r-- | srv/src/http/tpl.go | 18 | ||||
-rw-r--r-- | srv/src/http/tpl/assets.html | 6 | ||||
-rw-r--r-- | srv/src/http/tpl/edit-post.html | 4 | ||||
-rw-r--r-- | srv/src/http/tpl/load-csrf.html | 13 | ||||
-rw-r--r-- | srv/src/http/tpl/posts.html | 5 |
7 files changed, 10 insertions, 105 deletions
diff --git a/srv/src/http/api.go b/srv/src/http/api.go index da54c9c..4143200 100644 --- a/srv/src/http/api.go +++ b/srv/src/http/api.go @@ -164,8 +164,6 @@ func (a *api) Shutdown(ctx context.Context) error { func (a *api) apiHandler() http.Handler { mux := http.NewServeMux() - mux.Handle("/csrf", a.getCSRFTokenHandler()) - mux.Handle("/pow/challenge", a.newPowChallengeHandler()) mux.Handle("/pow/check", a.requirePowMiddleware( @@ -250,11 +248,10 @@ func (a *api) handler() http.Handler { h := apiutil.MethodMux(map[string]http.Handler{ "GET": applyMiddlewares( mux, - setCSRFMiddleware, ), "*": applyMiddlewares( mux, - checkCSRFMiddleware, + a.checkCSRFMiddleware, addResponseHeadersMiddleware(map[string]string{ "Cache-Control": "no-store, max-age=0", "Pragma": "no-cache", diff --git a/srv/src/http/csrf.go b/srv/src/http/csrf.go index 7a45269..d0f7b6a 100644 --- a/srv/src/http/csrf.go +++ b/srv/src/http/csrf.go @@ -3,76 +3,26 @@ package http import ( "errors" "net/http" + "net/url" "github.com/mediocregopher/blog.mediocregopher.com/srv/http/apiutil" ) -const ( - csrfTokenCookieName = "csrf_token" - csrfTokenHeaderName = "X-CSRF-Token" - csrfTokenFormName = "csrfToken" -) - -func setCSRFMiddleware(h http.Handler) http.Handler { - return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - - csrfTok, err := apiutil.GetCookie(r, csrfTokenCookieName, "") - - if err != nil { - apiutil.InternalServerError(rw, r, err) - return - - } else if csrfTok == "" { - http.SetCookie(rw, &http.Cookie{ - Name: csrfTokenCookieName, - Value: apiutil.RandStr(32), - Secure: true, - }) - } - - h.ServeHTTP(rw, r) - }) -} - -func checkCSRFMiddleware(h http.Handler) http.Handler { +func (a *api) checkCSRFMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - csrfTok, err := apiutil.GetCookie(r, csrfTokenCookieName, "") - + refererURL, err := url.Parse(r.Referer()) if err != nil { - apiutil.InternalServerError(rw, r, err) + apiutil.BadRequest(rw, r, errors.New("invalid Referer")) return } - givenCSRFTok := r.Header.Get(csrfTokenHeaderName) - if givenCSRFTok == "" { - givenCSRFTok = r.FormValue(csrfTokenFormName) - } - - if csrfTok == "" || givenCSRFTok != csrfTok { - apiutil.BadRequest(rw, r, errors.New("invalid CSRF token")) + if refererURL.Scheme != a.params.PublicURL.Scheme || + refererURL.Host != a.params.PublicURL.Host { + apiutil.BadRequest(rw, r, errors.New("invalid Referer")) return } h.ServeHTTP(rw, r) }) } - -func (a *api) getCSRFTokenHandler() http.Handler { - - return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - - csrfTok, err := apiutil.GetCookie(r, csrfTokenCookieName, "") - - if err != nil { - apiutil.InternalServerError(rw, r, err) - return - } - - apiutil.JSONResult(rw, r, struct { - CSRFToken string - }{ - CSRFToken: csrfTok, - }) - }) -} diff --git a/srv/src/http/tpl.go b/srv/src/http/tpl.go index 8654569..fb0f5bd 100644 --- a/srv/src/http/tpl.go +++ b/srv/src/http/tpl.go @@ -5,7 +5,6 @@ import ( "fmt" "html/template" "io/fs" - "log" "net/http" "path/filepath" "strings" @@ -100,21 +99,12 @@ func (a *api) mustParseTpl(name string) *template.Template { func (a *api) mustParseBasedTpl(name string) *template.Template { tpl := a.mustParseTpl(name) - tpl = template.Must(tpl.New("load-csrf.html").Parse(mustReadTplFile("load-csrf.html"))) tpl = template.Must(tpl.New("base.html").Parse(mustReadTplFile("base.html"))) return tpl } type tplData struct { - Payload interface{} - CSRFToken string -} - -func (t tplData) CSRFFormInput() template.HTML { - return template.HTML(fmt.Sprintf( - `<input type="hidden" name="%s" class="csrfHiddenInput" />`, - csrfTokenFormName, - )) + Payload interface{} } // executeTemplate expects to be the final action in an http.Handler @@ -123,11 +113,8 @@ func executeTemplate( tpl *template.Template, payload interface{}, ) { - csrfToken, _ := apiutil.GetCookie(r, csrfTokenCookieName, "") - tplData := tplData{ - Payload: payload, - CSRFToken: csrfToken, + Payload: payload, } if err := tpl.Execute(rw, tplData); err != nil { @@ -141,7 +128,6 @@ func executeTemplate( func (a *api) executeRedirectTpl( rw http.ResponseWriter, r *http.Request, url string, ) { - log.Printf("here url:%q", url) executeTemplate(rw, r, a.redirectTpl, struct { URL string }{ diff --git a/srv/src/http/tpl/assets.html b/srv/src/http/tpl/assets.html index 86e0ba5..41d470c 100644 --- a/srv/src/http/tpl/assets.html +++ b/srv/src/http/tpl/assets.html @@ -1,7 +1,5 @@ {{ define "body" }} -{{ $csrfFormInput := .CSRFFormInput }} - <h2>Upload Asset</h2> <p> @@ -10,7 +8,6 @@ </p> <form action="{{ BlogURL "assets/" }}" method="POST" enctype="multipart/form-data"> - {{ $csrfFormInput }} <div class="row"> <div class="four columns"> <input type="text" placeholder="Unique ID" name="id" /> @@ -37,7 +34,6 @@ method="POST" style="margin-bottom: 0;" > - {{ $csrfFormInput }} <input type="submit" value="Delete" /> </form> </td> @@ -46,8 +42,6 @@ </table> -{{ template "load-csrf.html" . }} - {{ end }} {{ template "base.html" . }} diff --git a/srv/src/http/tpl/edit-post.html b/srv/src/http/tpl/edit-post.html index 48af882..1a81df4 100644 --- a/srv/src/http/tpl/edit-post.html +++ b/srv/src/http/tpl/edit-post.html @@ -2,8 +2,6 @@ <form method="POST" action="{{ BlogURL "posts/" }}"> - {{ .CSRFFormInput }} - <div class="row"> <div class="columns six"> @@ -99,8 +97,6 @@ </form> - {{ template "load-csrf.html" . }} - {{ end }} {{ template "base.html" . }} diff --git a/srv/src/http/tpl/load-csrf.html b/srv/src/http/tpl/load-csrf.html deleted file mode 100644 index b0757f9..0000000 --- a/srv/src/http/tpl/load-csrf.html +++ /dev/null @@ -1,13 +0,0 @@ -<script async type="module" src="{{ StaticURL "api.js" }}"></script> - -<script type="text/javascript"> - (async () => { - const api = await import("{{ StaticURL "api.js" }}"); - const res = await api.call("/api/csrf"); - - const els = document.getElementsByClassName("csrfHiddenInput"); - for (let i = 0; i < els.length; i++) { - els[i].value = res.CSRFToken; - } - })(); -</script> diff --git a/srv/src/http/tpl/posts.html b/srv/src/http/tpl/posts.html index 0609ff6..885018d 100644 --- a/srv/src/http/tpl/posts.html +++ b/srv/src/http/tpl/posts.html @@ -18,8 +18,6 @@ {{ define "body" }} - {{ $csrfFormInput := .CSRFFormInput }} - <p style="text-align: center;"> <a href="{{ BlogURL "posts/" }}?edit"> <button>New Post</button> @@ -44,7 +42,6 @@ action="{{ PostURL .ID }}?method=delete" method="POST" > - {{ $csrfFormInput }} <input type="submit" value="Delete" /> </form> </td> @@ -55,8 +52,6 @@ {{ template "posts-nextprev" . }} - {{ template "load-csrf.html" . }} - {{ end }} {{ template "base.html" . }} |