introduce

This article describes how to implement server CSRF authentication logic through RK-boot.

What is CSRF?

Cross-site request forgery Cross-site Request Forgery, also known as one-click attack or session riding, usually abbreviated as CSRF or XSRF, Is a method of hijacking a user to perform unintended actions on a currently logged Web application.

In contrast to cross-site scripting (XSS), which exploits the user’s trust in a given site, CSRF exploits the site’s trust in the user’s Web browser.

What are the defenses?

There are several popular defense methods as follows. We use examples to implement the defense of adding checktoken.

1: token synchronization mode

2: Check the Referer field

3: Adds the check Token

Please visit the following address for the full tutorial:

  • rkdocs.netlify.app/cn

The installation

go get github.com/rookie-ninja/rk-boot
go get github.com/rookie-ninja/rk-grpc
Copy the code

Quick start

Rk-boot enables grPC-gateway for the gRPC service by default. The two protocols listen to the same port.

This version of the CSRF interceptor ADAPTS to grPC-Gateway, that is, only for Restful requests. GRPC protocol request, currently not supported.

1. Create the boot. Yaml

The boot.yaml file tells RK-boot how to start the gRPC service.

In the YAML file below, we declare one thing:

  • Start the CSRF interceptor, using the default parameters. The interceptor checks the x-CSRF-Token value in the request Header to determine if the Token is correct.
---
grpc:
  - name: greeter                     # Required
    port: 8080                        # Required
    enabled: true                     # Required
    interceptors:
      csrf:
        enabled: true                 # Optional, default: false
Copy the code

2. Create a main. Go

We added two Restful apis to grPC-Gateway.

  • GET /v1/greeter: Returns a CSRF Token generated by the server
  • POST/V1 /greeter: Verifies a 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"
	"fmt"
	"github.com/rookie-ninja/rk-boot"
	"github.com/rookie-ninja/rk-grpc/boot"
	"net/http"
)

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

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

	// Register handler in grpc-gateway
	grpcEntry := boot.GetEntry("greeter").(*rkgrpc.GrpcEntry)
	grpcEntry.GwMux.HandlePath("GET"."/v1/greeter".func(w http.ResponseWriter, r *http.Request, pathParams map[string]string) {
		w.Write([]byte(fmt.Sprintf("Hello %s!", r.URL.Query().Get("name"))))
	})

	grpcEntry.GwMux.HandlePath("POST"."/v1/greeter".func(w http.ResponseWriter, r *http.Request, pathParams map[string]string) {
		w.Write([]byte(fmt.Sprintf("Hello %s!", r.URL.Query().Get("name"})))))// Wait for shutdown sig
	boot.WaitForShutdownSig(context.Background())
}
Copy the code

3. Folder structure

.├ ── Go.tempo ├── go.tempo ├─ main. Go 0 directories, 4 filesCopy the code

4. Verify

  • Send a GET request to /v1/ Greeter and we will GET a 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=WyOJLwzhfUGAMDHglkuIRucdpalxolWg; Expires=Mon, 06 Dec 2021 18:38:45 GMT < Vary: Cookie < Date: Sun, 05 Dec 2021 18:38:45 GMT < Content-Length: 22 < {"Message":"Hello *!" }Copy the code
  • Send a POST request to /v1/greeter to provide a valid 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, 06 Dec 2021 18:40:13 GMT < Vary: Cookie < Date: Sun, 05 Dec 2021 18:40:13 GMT < Content-Length: 22 < {"Message":"Hello *!" }Copy the code
  • Send a POST request to /v1/ Greeter to 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, 05 Dec 2021 18:41:00 GMT < Content-Length: 92 < {"error":{"code":403,"status":"Forbidden","message":"invalid csrf token","details":[null]}}Copy the code

CSRF interceptor option

Rk-boot provides several CSRF interceptor options, and override options are not recommended except for special needs.

options describe type The default value
grpc.interceptors.csrf.enabled Start the CSRF interceptor boolean false
grpc.interceptors.csrf.tokenLength The length of the Token int 32
grpc.interceptors.csrf.tokenLookup Where to obtain the Token, please refer to the following introduction string “The header: X-ray CSRF Token -“
grpc.interceptors.csrf.cookieName The Cookie name string _csrf
grpc.interceptors.csrf.cookieDomain Cookie domain string “”
grpc.interceptors.csrf.cookiePath Cookie path string “”
grpc.interceptors.csrf.cookieMaxAge Cookie MaxAge (seconds) int 86400 (24 hours)
grpc.interceptors.csrf.cookieHttpOnly Cookie HTTP Only option bool false
grpc.interceptors.csrf.cookieSameSite Cookie SameSite option, supported [lax, strict, None, default] string “lax”
grpc.interceptors.csrf.ignorePrefix The Restful API Path verified by CSRF is ignored []string []

TokenLookup format

Currently, three methods are supported. The interceptor uses one of the following methods to look for tokens in the request.

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