83 lignes
2,1 Kio
Go
83 lignes
2,1 Kio
Go
|
package csrf
|
||
|
|
||
|
import (
|
||
|
"net/http"
|
||
|
"time"
|
||
|
|
||
|
"github.com/gorilla/securecookie"
|
||
|
)
|
||
|
|
||
|
// store represents the session storage used for CSRF tokens.
|
||
|
type store interface {
|
||
|
// Get returns the real CSRF token from the store.
|
||
|
Get(*http.Request) ([]byte, error)
|
||
|
// Save stores the real CSRF token in the store and writes a
|
||
|
// cookie to the http.ResponseWriter.
|
||
|
// For non-cookie stores, the cookie should contain a unique (256 bit) ID
|
||
|
// or key that references the token in the backend store.
|
||
|
// csrf.GenerateRandomBytes is a helper function for generating secure IDs.
|
||
|
Save(token []byte, w http.ResponseWriter) error
|
||
|
}
|
||
|
|
||
|
// cookieStore is a signed cookie session store for CSRF tokens.
|
||
|
type cookieStore struct {
|
||
|
name string
|
||
|
maxAge int
|
||
|
secure bool
|
||
|
httpOnly bool
|
||
|
path string
|
||
|
domain string
|
||
|
sc *securecookie.SecureCookie
|
||
|
}
|
||
|
|
||
|
// Get retrieves a CSRF token from the session cookie. It returns an empty token
|
||
|
// if decoding fails (e.g. HMAC validation fails or the named cookie doesn't exist).
|
||
|
func (cs *cookieStore) Get(r *http.Request) ([]byte, error) {
|
||
|
// Retrieve the cookie from the request
|
||
|
cookie, err := r.Cookie(cs.name)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
token := make([]byte, tokenLength)
|
||
|
// Decode the HMAC authenticated cookie.
|
||
|
err = cs.sc.Decode(cs.name, cookie.Value, &token)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return token, nil
|
||
|
}
|
||
|
|
||
|
// Save stores the CSRF token in the session cookie.
|
||
|
func (cs *cookieStore) Save(token []byte, w http.ResponseWriter) error {
|
||
|
// Generate an encoded cookie value with the CSRF token.
|
||
|
encoded, err := cs.sc.Encode(cs.name, token)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
cookie := &http.Cookie{
|
||
|
Name: cs.name,
|
||
|
Value: encoded,
|
||
|
MaxAge: cs.maxAge,
|
||
|
HttpOnly: cs.httpOnly,
|
||
|
Secure: cs.secure,
|
||
|
Path: cs.path,
|
||
|
Domain: cs.domain,
|
||
|
}
|
||
|
|
||
|
// Set the Expires field on the cookie based on the MaxAge
|
||
|
// If MaxAge <= 0, we don't set the Expires attribute, making the cookie
|
||
|
// session-only.
|
||
|
if cs.maxAge > 0 {
|
||
|
cookie.Expires = time.Now().Add(
|
||
|
time.Duration(cs.maxAge) * time.Second)
|
||
|
}
|
||
|
|
||
|
// Write the authenticated cookie to the response.
|
||
|
http.SetCookie(w, cookie)
|
||
|
|
||
|
return nil
|
||
|
}
|