Skip to content

Commit

Permalink
feat: add csrf example (cloudwego#60)
Browse files Browse the repository at this point in the history
* feat: add csrf example

* feat: add license to each file and update dependencies

* fix: Handling possible errors in the error log

* fix: Use two paragraphs

* doc: add links for csrf example

* fix: add some comments to explain the different meanings corresponding to different return values.

* fix: fix conflict

* fix: fix conflict

* fix: add license to each file and replaced obsolete function

* style: use gofumpt

Co-authored-by: kinggo <[email protected]>
  • Loading branch information
Claude-Zq and li-jin-gou authored Jan 9, 2023
1 parent cb30d52 commit 67590ad
Show file tree
Hide file tree
Showing 13 changed files with 378 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ You can enter the example for information about "How to run"
- [middleware:](middleware) Example of using middleware of hertz
- [basicauth:](middleware/basicauth) Example of using BasicAuth middleware
- [cors:](middleware/CORS) Example of using CORS middleware
- [csrf:](middleware/csrf) Example of using csrf middleware
- [custom:](middleware/custom) Example of using custom middleware
- [pprof:](middleware/pprof) Example of using pprof middleware
- [requestid:](middleware/requestid) Example of using RequestID middleware
Expand Down
1 change: 1 addition & 0 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
- [middleware:](middleware) 使用 hertz 中间件的示例
- [basicauth:](middleware/basicauth) 使用 BasicAuth 中间件的示例
- [cors:](middleware/CORS) 使用 CORS 中间件的示例
- [csrf:](middleware/csrf) 使用 csrf 中间件示例
- [custom:](middleware/custom) 自定义 middleware 的示例
- [pprof:](middleware/pprof) 使用 pprof 中间件的示例
- [requestid:](middleware/requestid) 使用 RequestID 中间件的示例
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.3 // indirect
github.com/hertz-contrib/cors v0.0.0-20220601061225-50f4e582beaf
github.com/hertz-contrib/csrf v0.1.1
github.com/hertz-contrib/gzip v0.0.1
github.com/hertz-contrib/logger/logrus v0.0.0-20221104075115-aecbfb39bbfe
github.com/hertz-contrib/logger/zap v0.0.0-20221104075115-aecbfb39bbfe
Expand All @@ -26,6 +27,7 @@ require (
github.com/hertz-contrib/registry/nacos v0.0.0-20220901103531-b8810bf778fb
github.com/hertz-contrib/requestid v1.1.0
github.com/hertz-contrib/reverseproxy v0.0.0-20220907134658-6a05798e1cc5
github.com/hertz-contrib/sessions v1.0.1
github.com/hertz-contrib/tracer v0.0.0-20220601062646-788b1565bdab
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/kitex-contrib/obs-opentelemetry v0.0.0-20220616115444-37518030dbb3
Expand Down
13 changes: 13 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw=
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/bytedance/go-tagexpr/v2 v2.9.2 h1:QySJaAIQgOEDQBLS3x9BxOWrnhqu5sQ+f6HaZIxD39I=
Expand Down Expand Up @@ -118,6 +119,7 @@ github.com/cloudwego/hertz v0.2.2-0.20220819075506-6fff4a1e7a9c/go.mod h1:GWWYlA
github.com/cloudwego/hertz v0.3.0/go.mod h1:GWWYlAVkq1gDu6vJd/XNciWsP6q0d4TrEKk5fpJYF04=
github.com/cloudwego/hertz v0.3.2/go.mod h1:hnv3B7eZ6kMv7CKFHT2OC4LU0mA4s5XPyu/SbixLcrU=
github.com/cloudwego/hertz v0.4.0/go.mod h1:QSD2254yaf43BIy4isrlfKR42R3uFAT+6G5CpeROOJs=
github.com/cloudwego/hertz v0.4.1/go.mod h1:K1U0RlU07CDeBINfHNbafH/3j9uSgIW8otbjUys3OPY=
github.com/cloudwego/hertz v0.4.2 h1:Ntfs5MdPoKeFSbyStU2drM4CizOkEfYWsB9s1Q3taPY=
github.com/cloudwego/hertz v0.4.2/go.mod h1:K1U0RlU07CDeBINfHNbafH/3j9uSgIW8otbjUys3OPY=
github.com/cloudwego/kitex v0.0.4/go.mod h1:EIjPJ4Dom2ornk7xDCdKpUpOnf4Tulevimh4Tn05OGc=
Expand Down Expand Up @@ -248,6 +250,7 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
Expand Down Expand Up @@ -283,9 +286,15 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
Expand Down Expand Up @@ -322,6 +331,8 @@ github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 h1:yE9ULgp02BhY
github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8/go.mod h1:Nhe/DM3671a5udlv2AdV2ni/MZzgfv2qrPL5nIi3EGQ=
github.com/hertz-contrib/cors v0.0.0-20220601061225-50f4e582beaf h1:ZAxm2v6m6uhdlRZkmfcdFJm9P3FG7VQIQxC5Hkx8Li0=
github.com/hertz-contrib/cors v0.0.0-20220601061225-50f4e582beaf/go.mod h1:45j0uowS7Wuijes/UKkxrszUM7Hs6E49TY0M27Fu560=
github.com/hertz-contrib/csrf v0.1.1 h1:53HxseVzpW4JEUJ7ONAaQCyNBWXl+rn42LVqgwEQzRg=
github.com/hertz-contrib/csrf v0.1.1/go.mod h1:z6CW935kPp1qy1XHXL7memdWInXXTc3OiMLp/cEmZQY=
github.com/hertz-contrib/gzip v0.0.1 h1:fPCnSZIDT4Gd8ZTuoCCJXek0opUsN89T2djdEW7Awr4=
github.com/hertz-contrib/gzip v0.0.1/go.mod h1:Fom/vnPMLA3UJ/P8fsZO8izjWG82m53BGO48lW1U1l8=
github.com/hertz-contrib/logger/logrus v0.0.0-20221104075115-aecbfb39bbfe h1:zN6bQ8EVxZmnUfcU2zVU63AmDJFg1lcvRKL4T66MK7M=
Expand All @@ -348,6 +359,8 @@ github.com/hertz-contrib/requestid v1.1.0 h1:+y1cuNlNX2KUoEC1SnBJ6M55/TlMTx3M9yx
github.com/hertz-contrib/requestid v1.1.0/go.mod h1:+l5CbZl//cSUoos421fnDFKQ6YYlVHcYc3Ri7AS8DUA=
github.com/hertz-contrib/reverseproxy v0.0.0-20220907134658-6a05798e1cc5 h1:kK7lkrXhoFvX7TIrd36V+OGpdEmcFzoiAYEkWiLX/5w=
github.com/hertz-contrib/reverseproxy v0.0.0-20220907134658-6a05798e1cc5/go.mod h1:uq9j5/W/pFmkYZ4a5Lvn0xzVlO9mhZAtlcddRMGm7kc=
github.com/hertz-contrib/sessions v1.0.1 h1:2puqvNqzyuPC3+5gzMRS+xhvGdNq3Ux7OVEewLSJbAk=
github.com/hertz-contrib/sessions v1.0.1/go.mod h1:gyVq7zq5emvSTLpp4VrlLOXjnajorYZ1hH4ZSX9Afb0=
github.com/hertz-contrib/tracer v0.0.0-20220601062646-788b1565bdab h1:Cp4ka30wJ+yOnBKNyGZSQp+G83NSOyE1jtTA3J7u0Ws=
github.com/hertz-contrib/tracer v0.0.0-20220601062646-788b1565bdab/go.mod h1:DDjNWpsO4B1fsYscviQEAhET8PzHOpowaPbuQfNpLmY=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
Expand Down
1 change: 1 addition & 0 deletions middleware/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
You can learn about how to use hertz middleware:
* basicauth: how to use basic authorization for request
* CORS(Cross-Origin Resource Sharing): how to use cors middleware for cross-origin request
* csrf: how to use csrf middleware
* custom: how to customize middleware
* pporf: how to use pprof middleware
* requestid: how to use requestid middleware
Expand Down
11 changes: 11 additions & 0 deletions middleware/csrf/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# csrf

You can learn about how to use csrf for hertz:

* [default](./default): This is using csrf by default
* [custom_secret](./custom_secret): How to set the secret to generate a csrf-token
* [custom_errorFunc](./custom_errorfunc): How to customize error handling functions
* [custom_ignoreMethods](./custom_ignoremethods): How to set up custom methods that do not need to be protected
* [custom_keyLookup](./custom_keylookup): How to customize extractor by setting keyLookup
* [custom_extractor](./custom_extractor): How to customize extractor directly
* [custom_next](./custom_next): How to skip the csrf middleware in certain situations
71 changes: 71 additions & 0 deletions middleware/csrf/custom_errorfunc/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright 2022 CloudWeGo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package main

import (
"context"
"errors"
"fmt"
"net/http"

"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/hertz-contrib/csrf"
"github.com/hertz-contrib/sessions"
"github.com/hertz-contrib/sessions/cookie"
)

var (
errMissingHeader = errors.New("[CSRF] missing csrf token in header")
errMissingQuery = errors.New("[CSRF] missing csrf token in query")
errMissingParam = errors.New("[CSRF] missing csrf token in param")
errMissingForm = errors.New("[CSRF] missing csrf token in form")
errMissingSalt = errors.New("[CSRF] missing salt")
errInvalidToken = errors.New("[CSRF] invalid token")
)

// myErrFunc is executed when an error occurs in csrf middleware.
func myErrFunc(_ context.Context, ctx *app.RequestContext) {
err := ctx.Errors.Last()
switch err {
case errMissingForm, errMissingParam, errMissingHeader, errMissingQuery:
ctx.String(http.StatusBadRequest, err.Error()) // extract csrf-token failed
case errMissingSalt:
fmt.Println(err.Error())
ctx.String(http.StatusInternalServerError, err.Error()) // get salt failed,which is unexpected
case errInvalidToken:
ctx.String(http.StatusBadRequest, err.Error()) // csrf-token is invalid
}
ctx.Abort()
}

func main() {
h := server.Default()

store := cookie.NewStore([]byte("store"))
h.Use(sessions.New("csrf-session", store))
h.Use(csrf.New(csrf.WithErrorFunc(myErrFunc)))

h.GET("/protected", func(c context.Context, ctx *app.RequestContext) {
ctx.String(200, csrf.GetToken(ctx))
})
h.POST("/protected", func(c context.Context, ctx *app.RequestContext) {
ctx.String(200, "CSRF token is valid")
})

h.Spin()
}
53 changes: 53 additions & 0 deletions middleware/csrf/custom_extractor/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2022 CloudWeGo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package main

import (
"context"
"errors"

"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/hertz-contrib/csrf"
"github.com/hertz-contrib/sessions"
"github.com/hertz-contrib/sessions/cookie"
)

func myExtractor(_ context.Context, ctx *app.RequestContext) (string, error) {
token := ctx.FormValue("csrf-token")
if token == nil {
return "", errors.New("missing token in form-data") // get csrf-token from form-data failed
}
return string(token), nil
}

func main() {
h := server.Default()

store := cookie.NewStore([]byte("secret"))
h.Use(sessions.New("csrf-session", store))
h.Use(csrf.New(csrf.WithExtractor(myExtractor)))

h.GET("/protected", func(c context.Context, ctx *app.RequestContext) {
ctx.String(200, csrf.GetToken(ctx))
})
h.POST("/protected", func(c context.Context, ctx *app.RequestContext) {
ctx.String(200, "CSRF token is valid")
})

h.Spin()
}
44 changes: 44 additions & 0 deletions middleware/csrf/custom_ignoremethods/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2022 CloudWeGo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package main

import (
"context"

"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/hertz-contrib/csrf"
"github.com/hertz-contrib/sessions"
"github.com/hertz-contrib/sessions/cookie"
)

func main() {
h := server.Default()

store := cookie.NewStore([]byte("secret"))
h.Use(sessions.New("csrf-session", store))
h.Use(csrf.New(csrf.WithIgnoredMethods([]string{"GET", "HEAD", "TRACE"})))

h.GET("/protected", func(c context.Context, ctx *app.RequestContext) {
ctx.String(200, csrf.GetToken(ctx))
})

h.OPTIONS("/protected", func(c context.Context, ctx *app.RequestContext) {
ctx.String(200, "success")
})
h.Spin()
}
43 changes: 43 additions & 0 deletions middleware/csrf/custom_keylookup/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2022 CloudWeGo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main

import (
"context"

"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/hertz-contrib/csrf"
"github.com/hertz-contrib/sessions"
"github.com/hertz-contrib/sessions/cookie"
)

func main() {
h := server.Default()

store := cookie.NewStore([]byte("store"))
h.Use(sessions.New("csrf-session", store))
h.Use(csrf.New(csrf.WithKeyLookUp("form:csrf")))

h.GET("/protected", func(c context.Context, ctx *app.RequestContext) {
ctx.String(200, csrf.GetToken(ctx))
})
h.POST("/protected", func(c context.Context, ctx *app.RequestContext) {
ctx.String(200, "CSRF token is valid")
})

h.Spin()
}
49 changes: 49 additions & 0 deletions middleware/csrf/custom_next/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2022 CloudWeGo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main

import (
"context"

"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/hertz-contrib/csrf"
"github.com/hertz-contrib/sessions"
"github.com/hertz-contrib/sessions/cookie"
)

func isPostMethod(_ context.Context, ctx *app.RequestContext) bool {
if string(ctx.Method()) == "POST" {
return true
} else {
return false
}
}

func main() {
h := server.Default()

store := cookie.NewStore([]byte("store"))
h.Use(sessions.New("csrf-session", store))

// skip csrf middleware when request method is post
h.Use(csrf.New(csrf.WithNext(isPostMethod)))

h.POST("/protected", func(c context.Context, ctx *app.RequestContext) {
ctx.String(200, "success even no csrf-token in header")
})
h.Spin()
}
Loading

0 comments on commit 67590ad

Please sign in to comment.