Skip to content

Commit

Permalink
给jwt插件添加验证csrf令牌机制
Browse files Browse the repository at this point in the history
  • Loading branch information
yishui01 committed Mar 4, 2020
1 parent 3839931 commit c29608b
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 5 deletions.
1 change: 1 addition & 0 deletions examples/jwt.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"tokenLookup": "token lookup, [header|query|cookie:Authorization]",
"authSchema": "jwt schema, [Bearer]",
"renewTokenHeaderName": "the header name for new token in the response header",
"csrfHeaderName": "the header name for CSRFToken",
"redis": {
"addr": "127.0.0.1:6379",
"maxActive": "max connections, int",
Expand Down
1 change: 1 addition & 0 deletions examples/jwt_a_simple_working_one.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"tokenLookup": "header:Authorization",
"authSchema": "Bearer",
"renewTokenHeaderName": "",
"csrfHeaderName": "_csrf",
"redis": {
"addr": "127.0.0.1:6379",
"maxActive": 1000,
Expand Down
49 changes: 44 additions & 5 deletions pkg/proxy/filter_jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ import (

const (
// besides checking token is legitimate or not, it checks whether token exists in redis
actionTokenInRedis string = "token_in_redis"
actionTokenInRedis string = "token_in_redis"
// besides checking token is legitimate or not, it checks whether token exists in redis and the value is the csrfToken value
actionTokenAndCSRFInRedis string = "token_and_csrf_in_redis"
// update token's TTL
actionRenewByRaw string = "renew_by_raw"
actionRenewByRaw string = "renew_by_raw"
// update token's TTL and in the same time put new token in redis, previous token invalid
actionRenewByRedis string = "renew_by_redis"
actionRenewByRedis string = "renew_by_redis"
// fetch fields from token and put them in header which is redirected to a backend server who is unbeknownst to JWT
actionFetchToHeader string = "fetch_to_header"
actionFetchToCookie string = "fetch_to_cookie"
Expand All @@ -31,8 +33,10 @@ const (
)

var (
errJWTMissing = errors.New("missing jwt token")
errJWTInvalid = errors.New("invalid jwt token")
errJWTMissing = errors.New("missing jwt token")
errJWTInvalid = errors.New("invalid jwt token")
errCSRFMissing = errors.New("missing csrf token")
errCSRFInvalid = errors.New("invalid csrf token")
)

type tokenGetter func(filter.Context) (string, error)
Expand All @@ -43,6 +47,7 @@ type JWTCfg struct {
Secret string `json:"secret"`
Method string `json:"method"`
TokenLookup string `json:"tokenLookup"`
CSRFHeaderName string `json:"csrfHeaderName"`
AuthSchema string `json:"authSchema"`
RenewTokenHeaderName string `json:"renewTokenHeaderName,omitempty"`
Redis *Redis `json:"redis,omitempty"`
Expand Down Expand Up @@ -70,6 +75,7 @@ type JWTFilter struct {
cfg *JWTCfg
secretBytes []byte
getter tokenGetter
csrfGetter tokenGetter
redisPool *redis.Pool
leaseTTLDuration time.Duration
signing *jwt.SigningMethodHMAC
Expand Down Expand Up @@ -199,6 +205,7 @@ func (f *JWTFilter) initTokenLookup() {
case "cookie":
f.getter = jwtFromCookie(parts[1])
}
f.csrfGetter = jwtFromHeader(f.cfg.CSRFHeaderName, "")
}

func (f *JWTFilter) initActions() error {
Expand All @@ -208,6 +215,8 @@ func (f *JWTFilter) initActions() error {
switch c.Method {
case actionTokenInRedis:
f.actions = append(f.actions, f.tokenInRedisAction)
case actionTokenAndCSRFInRedis:
f.actions = append(f.actions, f.actionTokenAndCSRFInRedis)
case actionRenewByRaw:
f.actions = append(f.actions, f.renewByRawAction)
case actionRenewByRedis:
Expand Down Expand Up @@ -322,6 +331,36 @@ func (f *JWTFilter) tokenInRedisAction(args map[string]interface{}, token string
return value, err
}

func (f *JWTFilter) actionTokenAndCSRFInRedis(args map[string]interface{}, token string, claims jwt.MapClaims, c filter.Context) (bool, error) {
if f.cfg.Redis == nil {
return false, fmt.Errorf("redis not setting")
}

var buf bytes.Buffer
buf.WriteString(args["prefix"].(string))
buf.WriteString(token)
key := hack.SliceToString(buf.Bytes())

conn := f.getRedis()
value, err := redis.String(conn.Do("GET", key))
conn.Close()

if err != nil {
return false, err
}
csrfToken, err := f.csrfGetter(c)
if err != nil {
if err == errJWTMissing {
err = errCSRFMissing
}
return false, err
}
if value != csrfToken {
return false, errCSRFInvalid
}
return true, err
}

func (f *JWTFilter) fetchToHeader(args map[string]interface{}, token string, claims jwt.MapClaims, c filter.Context) (bool, error) {
var buf bytes.Buffer
prefix := args["prefix"].(string)
Expand Down

0 comments on commit c29608b

Please sign in to comment.