Example #1
0
// TemplateField is a template helper for html/template that provides an <input> field
// populated with a CSRF token.
//
// Example:
//
//      // The following tag in our form.tmpl template:
//      {{ .csrfField }}
//
//      // ... becomes:
//      <input type="hidden" name="gorilla.csrf.Token" value="<token>">
//
func TemplateField(r *http.Request) template.HTML {
	name, ok := context.GetOk(r, FormKey)
	if ok {
		fragment := fmt.Sprintf(`<input type="hidden" name="%s" value="%s">`,
			name, Token(r))

		return template.HTML(fragment)
	}

	return template.HTML("")
}
Example #2
0
File: gf.go Project: goframework/gf
// Protect is HTTP middleware that provides Cross-Site Request Forgery
// protection.
//
// It securely generates a masked (unique-per-request) token that
// can be embedded in the HTTP response (e.g. form field or HTTP header).
// The original (unmasked) token is stored in the session, which is inaccessible
// by an attacker (provided you are using HTTPS). Subsequent requests are
// expected to include this token, which is compared against the session token.
// Requests that do not provide a matching token are served with a HTTP 403
// 'Forbidden' error response.
func csrfProtectHTTP(ctx *Context) bool {
	// No CSRF protect
	if mCsrfProtection == nil {
		return true
	}

	if v, _ := ctx.GetBool(_IS_CSRF_PROTECTED); v {
		return true
	}

	// Retrieve the token from the session.
	// An error represents either a cookie that failed HMAC validation
	// or that doesn't exist.
	r := ctx.r
	w := ctx.w

	realToken, err := mCsrfProtection.St.Get(r)
	if err != nil || len(realToken) != csrf.TokenLength {
		// If there was an error retrieving the token, the token doesn't exist
		// yet, or it's the wrong length, generate a new token.
		// Note that the new token will (correctly) fail validation downstream
		// as it will no longer match the request token.
		realToken, err = csrf.GenerateRandomBytes(csrf.TokenLength)
		if err != nil {
			csrf.EnvError(r, err)
			mCsrfProtection.Opts.ErrorHandler.ServeHTTP(w, r)
			return false
		}

		// Save the new (real) token in the session store.
		err = mCsrfProtection.St.Save(realToken, w)
		if err != nil {
			csrf.EnvError(r, err)
			mCsrfProtection.Opts.ErrorHandler.ServeHTTP(w, r)
			return false
		}
	}

	csrfToken := csrf.Mask(realToken, r)

	ctx.ViewData["csrfKey"] = csrf.TokenKey
	ctx.ViewData["csrfToken"] = csrfToken
	ctx.ViewData[csrf.TemplateTag] = template.HTML(fmt.Sprintf(`<input type="hidden" name="%s" value="%s">`, csrf.TokenKey, csrfToken))

	// HTTP methods not defined as idempotent ("safe") under RFC7231 require
	// inspection.
	if !csrf.Contains(csrf.SafeMethods, r.Method) {
		// Enforce an origin check for HTTPS connections. As per the Django CSRF
		// implementation (https://goo.gl/vKA7GE) the Referer header is almost
		// always present for same-domain HTTP requests.
		if r.URL.Scheme == "https" {
			// Fetch the Referer value. Call the error handler if it's empty or
			// otherwise fails to parse.
			referer, err := url.Parse(r.Referer())
			if err != nil || referer.String() == "" {
				csrf.EnvError(r, csrf.ErrNoReferer)
				mCsrfProtection.Opts.ErrorHandler.ServeHTTP(w, r)
				return false
			}

			if csrf.SameOrigin(r.URL, referer) == false {
				csrf.EnvError(r, csrf.ErrBadReferer)
				mCsrfProtection.Opts.ErrorHandler.ServeHTTP(w, r)
				return false
			}
		}

		// If the token returned from the session store is nil for non-idempotent
		// ("unsafe") methods, call the error handler.
		if realToken == nil {
			csrf.EnvError(r, csrf.ErrNoToken)
			mCsrfProtection.Opts.ErrorHandler.ServeHTTP(w, r)
			return false
		}

		// Retrieve the combined token (pad + masked) token and unmask it.
		requestToken := csrf.Unmask(mCsrfProtection.RequestToken(r))

		// Compare the request token against the real token
		if !csrf.CompareTokens(requestToken, realToken) {
			csrf.EnvError(r, csrf.ErrBadToken)
			mCsrfProtection.Opts.ErrorHandler.ServeHTTP(w, r)
			return false
		}
	}

	// Set the Vary: Cookie header to protect clients from caching the response.
	w.Header().Add("Vary", "Cookie")
	ctx.Set(_IS_CSRF_PROTECTED, true)
	return true
}