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".