简体   繁体   中英

Gorilla CSRF - Forbidden - CSRF token invalid - fails when there are two forms

I'm adding in CSRF token validation and I'm running into a problem where I have two forms on a page and one of them will submit successfully and the other will not. I'm not doing AJAX requests, I'm simply using hidden input fields. If I submit the form when it is the only one on the page, it submits without issue. If I submit it on a page with more than one form, it fails.

Below is the template code for my two forms

{{if .IsAuthenticated}}
  <form action='/admin/logout' method='POST'>
    <button>Logout</button>
    {{.CsrfField}}
  </form>
{{end}}
<form action='/admin/stuff/create' method='POST'>
{{with .Form}}
  <div>
    <label>Title:</label>
    <input type='text' name='title' value='{{.Get "title"}}'>
  </div>
  <div>
    <input type='submit' value='Publish stuff'>
  </div>
{{end}}
{{.CsrfField}}
</form>

And this is what the generated HTML looks like. Both appear to be valid.

在此处输入图像描述

When I click the "Logout" button though, I get the Forbidden - CSRF token invalid error, but clicking the create input value in the second form always works.

The logout button is correctly validated when I attempt to use it on the home page which is "/admin/" but it does not work on any of the other pages "/admin/snippet/:id" or "/admin/snippet/create". The Logout button is part of a base template, so it appears on every page, so there shouldn't be anything different in how it appears on any page.

I've read other SO posts about multiple forms & CSRF tokens on a page and I understand there should be no issue with multiple forms with the same information as long as you have each one in it's own form, it should be fine. So I am not sure where I am going wrong.

I found the issue. Currently the way that gorilla/csrf works, it does not like creating the masked token from one path and then sending that token off to another path. So in my situation, going from /admin/snippet/create to /admin/logout threw an error because it was expecting the path for the token to be /admin/snippet/<something> and so it threw an error.

This issue has been addressed in this PR: https://github.com/gorilla/csrf/pull/147 and essentially the solution is to set the default path yourself to something which all of your routes will contain, so in my case that was /admin

This is what my CSRF declaration looks like now in main.go

var csrfMiddleWare = csrf.Protect(
        []byte("<put your 32 character key here>"),
        csrf.Path("/admin"),
        csrf.Secure(false),
)

A note, if you had this issue and then apply this fix and it doesn't resolve the problem, trying testing in a separate browser as there may be some caching issues.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM