summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Picciano <mediocregopher@gmail.com>2022-05-24 17:42:00 -0600
committerBrian Picciano <mediocregopher@gmail.com>2022-05-24 17:42:00 -0600
commit08811a6da78c3f1f973b8f50a337ff4dc4ed9e2c (patch)
tree3fc8fa9025dbdc8099ea145e232f8b25547204b5
parent159638084e167047b86fd65382f50cd099d4eb48 (diff)
Replace CSRF token checking with Referer checking
-rw-r--r--srv/src/http/api.go5
-rw-r--r--srv/src/http/csrf.go64
-rw-r--r--srv/src/http/tpl.go18
-rw-r--r--srv/src/http/tpl/assets.html6
-rw-r--r--srv/src/http/tpl/edit-post.html4
-rw-r--r--srv/src/http/tpl/load-csrf.html13
-rw-r--r--srv/src/http/tpl/posts.html5
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" . }}