csrf

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 14, 2025 License: GPL-3.0 Imports: 8 Imported by: 1

README

CSRF Open in Gitpod

Tests Status Go Report Card PkgGoDev

Installation

go get -u github.com/dracory/csrf

Overview

This package provides simple CSRF token generation and validation with optional request-bound attributes and packaged expiry.

  • Tokens are generated via TokenGenerate(secret, opts...) and validated via TokenValidate(token, secret, opts...).
  • Callers treat the token as an opaque string. Packaging/unpackaging is handled internally.
  • You can bind request attributes (IP, User-Agent, Path, Method) into the token to reduce reuse.
  • Packaged tokens include an absolute expiry timestamp.

Quick Start

import (
    "net/http/httptest"
    "time"
    "github.com/dracory/csrf"
)

func example() bool {
    secret := "my-app-secret"
    r := httptest.NewRequest("POST", "/form/submit", nil)

    // Configure optional bindings and expiry
    opts := &csrf.Options{
        Request:      r,
        BindIP:       true,
        BindUserAgent:true,
        BindPath:     true,
        BindMethod:   true,
        ExpiresAt:    time.Now().UTC().Add(15 * time.Minute),
    }

    token := csrf.TokenGenerate(secret, opts)
    return csrf.TokenValidate(token, secret, opts)
}

Options

Options lets you opt-in to binding request attributes into the token and set a fixed expiry time:

  • Request *http.Request
    • The request whose attributes may be bound. If nil, binding flags are ignored.
  • BindIP bool
    • Mixes the client IP (X-Forwarded-For first, then X-Real-IP, then RemoteAddr) into the token.
  • BindUserAgent bool
    • Mixes the User-Agent header into the token.
  • BindPath bool
    • Mixes the request URL path into the token. Tokens become path-specific.
  • BindMethod bool
    • Mixes the HTTP method (e.g., POST) into the token. Tokens become method-specific.
  • ExpiresAt time.Time
    • Absolute expiry timestamp embedded into the packaged token. If zero, the library deterministically defaults to time.Now().UTC() + DefaultPackagedExpiry.

Notes:

  • If you pass no Options or a nil Options, the library uses defaults via an internal helper.
  • Binding only applies when Options.Request is non-nil and the corresponding Bind* flag is true.

Expiry

Tokens are packaged with an absolute expiry timestamp. During validation, the token is rejected if it is expired.

  • Default expiry window: DefaultPackagedExpiry (15 minutes) when Options.ExpiresAt is zero.
  • You can override ExpiresAt to any absolute UTC time when generating the token.

Binding Behavior Examples

  • Path binding (BindPath: true): tokens generated for /submit will not validate for /other.
  • Method binding (BindMethod: true): tokens generated for POST will not validate for GET.
  • IP or User-Agent binding: tokens will only validate when the client presents the same IP or UA as during generation.

API

// Generate a new CSRF token (opaque string) with optional bindings and expiry.
func TokenGenerate(secret string, opts ...*Options) string

// Validate a token previously produced by TokenGenerate.
// Unpacks the token, checks expiry, rebuilds the plaintext from secret + bound attributes,
// and bcrypt-compares.
func TokenValidate(csrfToken string, secret string, opts ...*Options) bool

Security Considerations

  • Use a strong, application-specific secret and keep it confidential.
  • Choose bindings appropriate for your deployment (e.g., be mindful of proxies/CDNs when enabling BindIP).
  • Prefer HTTPS to protect tokens in transit.

Testing

Run the test suite:

go test ./...

Documentation

Index

Constants

View Source
const CSRF_TOKEN_MIXIN = "HGEGY#G$tewdRwvweRftrsTcHyr"

CSRF_TOKEN_MIXIN is a static app-wide mix-in used to augment weak or empty secrets. It is not a secret unless sourced from configuration or environment.

View Source
const DefaultPackagedExpiry = 15 * time.Minute

DefaultPackagedExpiry is the default TTL for packaged tokens when Options.ExpiresAt is not set. Deterministic rule: issue time (UTC) + 15 minutes.

Variables

This section is empty.

Functions

func TokenGenerate

func TokenGenerate(secret string, opts ...*Options) string

TokenGenerate generates a CSRF token from the provided secret. Optional opts[0] can customize binding and expiry behavior. This function always returns a packaged token in the form "<bcrypt-hash>:<expiresUnix>" and binds the expiry into the hash input as "|exp:<expiresUnix>" to prevent tampering. If ExpiresAt is zero, the expiry defaults to now (UTC) + DefaultPackagedExpiry.

func TokenValidate

func TokenValidate(csrfToken string, secret string, opts ...*Options) bool

TokenValidate validates a packaged CSRF token produced by TokenGenerate.

This function internally unpacks the token format used by the generator. The function will:

  1. Unpackage the token and parse the embedded expiry timestamp.
  2. Reject the token if it is expired relative to time.Now().UTC().
  3. Rebuild the plaintext using the provided secret plus any request-bound attributes enabled via Options (e.g., BindIP, BindUserAgent, BindPath, BindMethod).
  4. Compare the bcrypt hash against the rebuilt plaintext (truncated to 72 bytes).

If opts is omitted or ExpiresAt is zero, a default expiry of now + DefaultPackagedExpiry is assumed for rebuilding the plaintext, keeping generation and validation consistent.

Types

type Options

type Options struct {
	// Request is the incoming HTTP request whose attributes can be bound into the token.
	// If nil, no request attributes are used regardless of the Bind* flags.
	Request *http.Request

	// BindIP, when true, mixes the client IP (X-Forwarded-For first, then X-Real-IP,
	// then RemoteAddr) into the token. This reduces token reuse from different IPs.
	BindIP bool

	// BindUserAgent, when true, mixes the request's User-Agent header into the token.
	// This helps constrain reuse across different clients/browsers.
	BindUserAgent bool

	// BindPath, when true, mixes the request URL path into the token, constraining
	// a token to a specific endpoint/path.
	BindPath bool

	// BindMethod, when true, mixes the HTTP method (e.g., POST) into the token.
	// Useful if you want tokens to be valid only for a given method.
	BindMethod bool

	// ExpiresAt sets the absolute expiry (UTC) for packaged tokens. If zero, the generator
	// uses a deterministic default of now (UTC) + DefaultPackagedExpiry.
	ExpiresAt time.Time
}

Options allows optional request binding for CSRF token generation/validation, and lets you set an absolute expiry for packaged tokens. All fields are optional. If Request is nil or a Bind* flag is false, that attribute is not used. ExpiresAt controls the expiry timestamp embedded into packaged tokens.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL