Gin security chapter-3: fast implementation of CSRF verification

introduce

This article describes how to rk-boot Implement the CSRF verification logic of the server.

What is CSRF?

Cross Site Request Forgery (English: Cross Site Request Forgery), also known as one click attack or session riding, usually abbreviated as CSRF or XSRF, is an attack method to coerce users to perform unintentional operations on the currently logged in Web application.

Compared with cross site scripting (XSS), XSS uses the user's trust in the specified website, and CSRF uses the website's trust in the user's web browser.

**What

What's the defense?

There are several popular defense methods. We implement the defense of [add verification Token] through examples.

1: Token synchronization mode 2: Check the Referer field 3: Add verification Token

Please visit the following address for a complete tutorial:

install

go get github.com/rookie-ninja/rk-boot/gin

Quick start

1. Create boot yaml

boot. The yaml file tells rk boot how to start the Gin service.

In the following YAML file, we declare one thing:

  • Turn on the CSRF interceptor and use the default parameters. The interceptor will check the value of X-CSRF-Token in the request Header to determine whether the Token is correct.
---
gin:
  - name: greeter                     # Required
    port: 8080                        # Required
    enabled: true                     # Required
    interceptors:
      csrf:
        enabled: true                 # Optional, default: false

2. Create main go

We added two restful APIs to Gin.

  • GET /v1/greeter: returns the CSRF Token generated by the server
  • POST /v1/greeter: verify CSRF Token
// Copyright (c) 2021 rookie-ninja
//
// Use of this source code is governed by an Apache-style
// license that can be found in the LICENSE file.
package main

import (
	"context"
	"github.com/gin-gonic/gin"
	"github.com/rookie-ninja/rk-boot"
	"github.com/rookie-ninja/rk-boot/gin"
	"net/http"
)

// Application entrance.
func main() {
	// Create a new boot instance.
	boot := rkboot.NewBoot()

	ginEntry := rkbootgin.GetGinEntry("greeter")
	// Register /v1/greeter GET
	ginEntry.Router.GET("/v1/greeter", func(ctx *gin.Context) {
		ctx.JSON(http.StatusOK, "Hello!")
	})
	// Register /v1/greeter POST
	ginEntry.Router.POST("/v1/greeter", func(ctx *gin.Context) {
		ctx.JSON(http.StatusOK, "Hello!")
	})

	// Bootstrap
	boot.Bootstrap(context.Background())

	// Wait for shutdown sig
	boot.WaitForShutdownSig(context.Background())
}

3. Folder structure

.
├── boot.yaml
├── go.mod
├── go.sum
└── main.go

0 directories, 4 files
  • go.mod
module github.com/rookie-ninja/rk-demo

go 1.16

require (
	github.com/rookie-ninja/rk-boot v1.4.0
	github.com/rookie-ninja/rk-boot/gin v1.2.12
)

4. Verification

  • Send a GET request to / v1/greeter and we will GET the CSRF Token.
$ curl -X GET -vs localhost:8080/v1/greeter
...
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Set-Cookie: _csrf=XVlBzgbaiCMRAjWwhTHctcuAxhxKQFDa; Expires=Mon, 27 Dec 2021 09:35:20 GMT
< Vary: Cookie
< Date: Sun, 26 Dec 2021 09:35:20 GMT
< Content-Length: 8
< 
* Connection #0 to host localhost left intact
"Hello!"* 
  • Send a POST request to / v1/greeter and provide a legal CSRF Token.
$ curl -X POST -v --cookie "_csrf=my-test-csrf-token" -H "X-CSRF-Token:my-test-csrf-token" localhost:8080/v1/greeter
...
> Cookie: _csrf=my-test-csrf-token
> X-CSRF-Token:my-test-csrf-token
> 
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Set-Cookie: _csrf=my-test-csrf-token; Expires=Mon, 27 Dec 2021 09:35:43 GMT
< Vary: Cookie
< Date: Sun, 26 Dec 2021 09:35:43 GMT
< Content-Length: 8
< 
* Connection #0 to host localhost left intact
"Hello!"* 
  • Send a POST request to / v1/greeter and provide an illegal CSRF Token.
$ curl -X POST -v -H "X-CSRF-Token:my-test-csrf-token" localhost:8080/v1/greeter
...
> X-CSRF-Token:my-test-csrf-token
> 
< HTTP/1.1 403 Forbidden
< Content-Type: application/json; charset=utf-8
< Date: Sun, 26 Dec 2021 09:36:18 GMT
< Content-Length: 91
< 
* Connection #0 to host localhost left intact
{"error":{"code":403,"status":"Forbidden","message":"invalid csrf token","details":[null]}}

CSRF interceptor options

Rk boot provides several CSRF interceptor options. Unless there are special needs, the override option is not recommended.

option

describe

type

Default value

gin.interceptors.csrf.enabled

Start CSRF interceptor

boolean

false

gin.interceptors.csrf.tokenLength

Token length

int

32

gin.interceptors.csrf.tokenLookup

Please refer to the introduction below for where to get the Token

string

"header:X-CSRF-Token"

gin.interceptors.csrf.cookieName

Cookie name

string

_csrf

gin.interceptors.csrf.cookieDomain

Cookie domain

string

""

gin.interceptors.csrf.cookiePath

Cookie path

string

""

gin.interceptors.csrf.cookieMaxAge

Cookie MaxAge (seconds)

int

86400 (24 hours)

gin.interceptors.csrf.cookieHttpOnly

Cookie HTTP Only option

bool

false

gin.interceptors.csrf.cookieSameSite

Cookie SameSite option, which supports lax, strict, none and default

string

"lax"

gin.interceptors.csrf.ignorePrefix

Ignoring Restful API Path for CSRF validation

[]string

[]

tokenLookup format

At present, the following three methods are supported. The interceptor will use one of the following methods to find a Token in the request.

  • Get from HTTP Header
  • Get from HTTP Form
  • Get from HTTP Query
// Optional. Default value "header:X-CSRF-Token".
// Possible values:
// - "header:<name>"
// - "form:<name>"
// - "query:<name>"
// Optional. Default value "header:X-CSRF-Token".

Keywords: Go Microservices Middleware gin csrf

Added by irwa82 on Sun, 26 Dec 2021 15:10:41 +0200