使用OAuth2客户端ID和密钥构建开源Golang应用的最佳实践

使用OAuth2客户端ID和密钥构建开源Golang应用的最佳实践 你好, 我是Go语言的新手。我编写了一个使用OAuth2与Gmail API交互的go应用程序。

我目前的想法是,在GitHub上在线提供应用程序的源代码,但不包含OAuth2客户端凭据,并让Travis CI将凭据作为环境变量提供。

你认为这是一种足够安全的隐藏客户端凭据的方法吗?或者客户端凭据是否也能通过构建的文件被发现?

6 回复

你是否在运行时使用环境变量?如果是,它们的值不会在构建时被放入二进制文件中。

更多关于使用OAuth2客户端ID和密钥构建开源Golang应用的最佳实践的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


环境变量的值并不包含在二进制文件中。

但是,构建过程真的需要凭据吗?你信任 Travis CI 来处理这些凭据吗?

如何能不是呢?我希望应用程序能存储它们,这样编译后的二进制文件就不必从其他地方查找凭据了。

我计划使用 Travis 来构建供他人使用的二进制文件。因此,关键点在于,我需要以某种方式插入凭据,使其隐藏在应用程序内部。这样一来,应用程序在运行时可以访问这些凭据,但用户无法窥探其内容。

在构建时使用的字符串会成为二进制文件的一部分。像 strings 这样的工具能够提取它们。

考虑以下 Go 程序:

package main

import "fmt"

func main() {
        fmt.Println("secret-password")
}

我使用 go build 构建了它,并从中提取了字符串:

$ go build .
$ ./app
secret-password
$ strings app | head
MCLQZWlA3o2hbFtaevAl/mCPiVsU6RFF8Y1sWQe0t/npVX9FnBJxrkc4OovmZA/TWk7bR3ktTP0dXlp4ur_
D$ H
D$(H
D$0H
L$pH
T$0H
;cpu.u
D$XH
T$0H
T$0H9
$ strings app | grep password
        morebuf={pc:advertise errorasyncpreemptoffbad debugCallV1force gc (idle)key has expiredmalloc deadlockmisaligned maskmissing mcache?ms: gomaxprocs=network is downno medium foundno such processnot a directoryrecovery failedruntime error: runtime: frame runtime: max = runtime: min = runtimer: bad pscan missed a gsecret-passwordstartm: m has pstopm holding p already; errno= mheap.sweepgen= not in ranges:

看,它就在那里:gsecret-passwordstartm

二进制文件中的密码并不安全。

在构建开源Golang应用时,将OAuth2客户端凭据作为环境变量处理是行业标准做法。客户端凭据不会通过编译后的二进制文件暴露,因为环境变量是在运行时注入的。

以下是一个安全的实现示例:

package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "golang.org/x/oauth2"
    "golang.org/x/oauth2/google"
    "google.golang.org/api/gmail/v1"
    "google.golang.org/api/option"
)

func main() {
    // 从环境变量获取凭据
    clientID := os.Getenv("OAUTH_CLIENT_ID")
    clientSecret := os.Getenv("OAUTH_CLIENT_SECRET")
    
    if clientID == "" || clientSecret == "" {
        log.Fatal("OAuth2凭据未设置")
    }

    // 配置OAuth2
    config := &oauth2.Config{
        ClientID:     clientID,
        ClientSecret: clientSecret,
        RedirectURL:  "http://localhost:8080/callback",
        Scopes:       []string{gmail.GmailReadonlyScope},
        Endpoint:     google.Endpoint,
    }

    // 获取认证URL(实际应用中需要完整的OAuth流程)
    authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
    fmt.Printf("访问此URL授权: %s\n", authURL)

    // 使用授权码交换令牌的示例
    ctx := context.Background()
    // 注意:这里需要实际的授权码
    // token, err := config.Exchange(ctx, "auth-code-here")
    
    // 创建Gmail服务
    // srv, err := gmail.NewService(ctx, option.WithTokenSource(config.TokenSource(ctx, token)))
}

.travis.yml中配置环境变量:

env:
  global:
    - secure: "加密的OAUTH_CLIENT_ID"
    - secure: "加密的OAUTH_CLIENT_SECRET"

编译后的二进制文件只包含环境变量名的引用,不包含实际值。用户运行应用时需要自行设置这些环境变量:

export OAUTH_CLIENT_ID="your-client-id"
export OAUTH_CLIENT_SECRET="your-client-secret"
./your-app

对于生产部署,可以使用Docker secrets、Kubernetes secrets或云平台的密钥管理服务来安全存储凭据。

回到顶部