CodeQL 文档

在 OAuth 2.0 URL 中使用常量 state

ID: go/constant-oauth2-state
Kind: path-problem
Security severity: 8.8
Severity: error
Precision: high
Tags:
   - security
   - external/cwe/cwe-352
Query suites:
   - go-code-scanning.qls
   - go-security-extended.qls
   - go-security-and-quality.qls

点击查看 CodeQL 代码库中的查询

OAuth 2.0 客户端必须对重定向 URI 实现 CSRF 保护,这通常是通过包含将请求绑定到用户的身份验证状态的“状态”值来完成的。Go OAuth 2.0 库允许您指定一个“状态”值,该值随后将包含在授权代码 URL 中。然后,远程身份验证服务器会在重定向回调中返回该状态,必须在该回调中对其进行验证。如果未这样做,则客户端容易受到 CSRF 攻击。

建议

始终包含一个唯一的、不可猜测的 state 值(提供给对 AuthCodeURL 函数的调用),该值也绑定到每个身份验证请求中用户的身份验证状态,然后在重定向回调中进行验证。

示例

第一个示例展示了如何使用常量状态(错误)。

package main

import (
	"golang.org/x/oauth2"
)

func main() {}

var stateStringVar = "state"

func badWithStringLiteralState() {
	conf := &oauth2.Config{
		ClientID:     "YOUR_CLIENT_ID",
		ClientSecret: "YOUR_CLIENT_SECRET",
		Scopes:       []string{"SCOPE1", "SCOPE2"},
		Endpoint: oauth2.Endpoint{
			AuthURL:  "https://provider.com/o/oauth2/auth",
			TokenURL: "https://provider.com/o/oauth2/token",
		},
	}

	url := conf.AuthCodeURL(stateStringVar)
	// ...
}

第二个示例展示了一种更好的实现方法。

package main

import (
	"crypto/rand"
	"encoding/base64"
	"net/http"

	"golang.org/x/oauth2"
)

func betterWithVariableStateReturned(w http.ResponseWriter) {
	conf := &oauth2.Config{
		ClientID:     "YOUR_CLIENT_ID",
		ClientSecret: "YOUR_CLIENT_SECRET",
		Scopes:       []string{"SCOPE1", "SCOPE2"},
		Endpoint: oauth2.Endpoint{
			AuthURL:  "https://provider.com/o/oauth2/auth",
			TokenURL: "https://provider.com/o/oauth2/token",
		},
	}

	state := generateStateOauthCookie(w)
	url := conf.AuthCodeURL(state)
	_ = url
	// ...
}
func generateStateOauthCookie(w http.ResponseWriter) string {
	b := make([]byte, 128)
	rand.Read(b)
	// TODO: save the state string to cookies or HTML storage,
	// and bind it to the authenticated status of the user.
	state := base64.URLEncoding.EncodeToString(b)

	return state
}

参考资料

  • ©GitHub, Inc.
  • 条款
  • 隐私