GoFrame framework (RK boot): fast implementation of CSRF verification

Posted by Cailean on Mon, 07 Feb 2022 09:01:54 +0100

introduce

This article describes how to pass 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's the defense?

There are several popular defense methods. We use examples to realize the defense of [add verification Token].

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/gf

Quick start

1. Create boot yaml

boot.yaml file will tell rk boot how to start gogf/gf 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.
---
gf:
  - name: greeter                     # Required
    port: 8080                        # Required
    enabled: true                     # Required
    interceptors:
      csrf:
        enabled: true                 # Optional, default: false

2. Create main go

We are gogf/gf Add two restful APIs to the.

  • GET /v1/hello: returns the CSRF Token generated by the server
  • POST /v1/hello: 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/gogf/gf/v2/net/ghttp"
	"github.com/rookie-ninja/rk-boot"
	"github.com/rookie-ninja/rk-boot/gf"
	"net/http"
)

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

	// Register handler
	entry := rkbootgf.GetGfEntry("greeter")
	entry.Server.BindHandler("/v1/hello", hello)

	// Bootstrap
	boot.Bootstrap(context.TODO())

	boot.WaitForShutdownSig(context.TODO())
}

func hello(ctx *ghttp.Request) {
	ctx.Response.WriteHeader(http.StatusOK)
	ctx.Response.WriteJson(map[string]string{
		"message": "hello!",
	})
}

3. Folder structure

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

0 directories, 4 files

4. Start main go

$ go run main.go
2022-02-07T15:02:03.187+0800    INFO    boot/gf_entry.go:600    Bootstrap gfEntry       {"eventId": "8238e90e-5cd0-4da7-9f9b-7bb9b1946978", "entryName": "greeter", "entryType": "GoFrame"}
------------------------------------------------------------------------
endTime=2022-02-07T15:02:03.188021+08:00
startTime=2022-02-07T15:02:03.187943+08:00
elapsedNano=78089
timezone=CST
ids={"eventId":"8238e90e-5cd0-4da7-9f9b-7bb9b1946978"}
app={"appName":"rk","appVersion":"","entryName":"greeter","entryType":"GoFrame"}
env={"arch":"amd64","az":"*","domain":"*","hostname":"lark.local","localIP":"10.8.0.2","os":"darwin","realm":"*","region":"*"}
payloads={"gfPort":8080}
counters={}
pairs={}
timing={}
remoteAddr=localhost
operation=Bootstrap
resCode=OK
eventStatus=Ended
EOE

5. Verification

  • Send a GET request to / v1/hello and we will GET the CSRF Token.
$ curl -X GET -vs localhost:8080/v1/hello
...
> Cookie: _csrf=my-test-csrf-token
> X-CSRF-Token:my-test-csrf-token
> 
< HTTP/1.1 200 OK
< Content-Type: application/json
< Server: GoFrame HTTP Server
< Set-Cookie: _csrf=my-test-csrf-token; Expires=Tue, 08 Feb 2022 07:02:45 GMT
< Trace-Id: 104af099fb6ed11600722376ab2d8a82
< Vary: Cookie
< Date: Mon, 07 Feb 2022 07:02:45 GMT
< Content-Length: 20
< 
* Connection #0 to host localhost left intact
{"message":"hello!"}
  • Send a POST request to / v1/hello 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/hello
...
> Cookie: _csrf=my-test-csrf-token
> X-CSRF-Token:my-test-csrf-token
> 
< HTTP/1.1 200 OK
< Content-Type: application/json
< Server: GoFrame HTTP Server
< Set-Cookie: _csrf=my-test-csrf-token; Expires=Tue, 08 Feb 2022 07:03:31 GMT
< Trace-Id: 90ded13e066fd1160172237663ed8fbb
< Vary: Cookie
< Date: Mon, 07 Feb 2022 07:03:31 GMT
< Content-Length: 20
< 
* Connection #0 to host localhost left intact
{"message":"hello!"}
  • Send a POST request to / v1/hello and provide an illegal CSRF Token.
$ curl -X POST -v -H "X-CSRF-Token:my-test-csrf-token" localhost:8080/v1/hello
...
> X-CSRF-Token:my-test-csrf-token
> 
< HTTP/1.1 403 Forbidden
< Server: GoFrame HTTP Server
< Trace-Id: c88c53630b6fd116027223761a59ee69
< Date: Mon, 07 Feb 2022 07:03:53 GMT
< Content-Length: 91
< Content-Type: text/plain; charset=utf-8
< 
* 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

gf.interceptors.csrf.enabled

Start CSRF interceptor

boolean

false

gf.interceptors.csrf.tokenLength

Token length

int

32

gf.interceptors.csrf.tokenLookup

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

string

"header:X-CSRF-Token"

gf.interceptors.csrf.cookieName

Cookie name

string

_csrf

gf.interceptors.csrf.cookieDomain

Cookie domain

string

""

gf.interceptors.csrf.cookiePath

Cookie path

string

""

gf.interceptors.csrf.cookieMaxAge

Cookie MaxAge (seconds)

int

86400 (24 hours)

gf.interceptors.csrf.cookieHttpOnly

Cookie HTTP Only option

bool

false

gf.interceptors.csrf.cookieSameSite

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

string

"lax"

gf.interceptors.csrf.ignorePrefix

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

Topics: Go Microservices Middleware csrf goframe