golang高效安全的Cookie编码解码插件库securecookie的使用

Golang高效安全的Cookie编码解码插件库securecookie的使用

securecookie是一个用于编码和解码安全Cookie值的Golang包,它比Gorilla的securecookie实现快3倍且不需要堆分配,同时提供同等的安全强度。

功能特点

  • 安全Cookie的值会被加密并使用消息认证码签名
  • 防止远程Cookie所有者知道或修改Cookie中的信息
  • 防止攻击者伪造假Cookie
  • 使用AES128和SHA256保证安全性
  • 与Gorilla securecookie不兼容,采用更简单高效的编码方式

安装

go get -u "github.com/chmike/securecookie"

使用示例

生成随机密钥

var key []byte = securecookie.MustGenerateRandomKey()

建议将密钥保存在文件中并使用hex.EncodeToString()编码,限制对该文件的访问。

创建Cookie对象

obj, err := securecookie.New("session", key, securecookie.Params{
    Path:     "/sec",           // 仅当URL以此路径开头时接收Cookie
    Domain:   "example.com",    // 仅当URL域名匹配时接收Cookie
    MaxAge:   3600,             // Cookie在设置后3600秒失效
    HTTPOnly: true,             // 禁止远程JavaScript代码访问
    Secure:   true,             // 仅通过HTTPS接收Cookie
    SameSite: securecookie.Lax, // 接收相同或子域名的Cookie
})
if err != nil {
    // 处理错误
}

或者使用MustNew()函数,在参数无效时会panic:

var obj = securecookie.MustNew("Auth", key, securecookie.Params{
    Path:     "/sec",
    Domain:   "example.com",
    MaxAge:   3600,
    HTTPOnly: true,
    Secure:   true,
    SameSite: securecookie.Lax,
})

设置Cookie值

var val = []byte("some value")
// w是http.ResponseWriter
if err := obj.SetValue(w, val); err != nil {
    // 处理错误
}

获取Cookie值

// r是*http.Request
val, err := obj.GetValue(buf, r) 
if err != nil {
  // 处理错误
}

删除Cookie

// w是http.ResponseWriter
if err := obj.Delete(w); err != nil {
  // 处理错误
}

完整示例

package main

import (
	"fmt"
	"log"
	"net/http"
	
	"github.com/chmike/securecookie"
)

var key = securecookie.MustGenerateRandomKey()
var sc = securecookie.MustNew("session", key, securecookie.Params{
	Path:     "/",
	MaxAge:   3600,
	HTTPOnly: true,
	Secure:   false, // 开发环境设为false,生产环境设为true
})

func main() {
	http.HandleFunc("/set/", setHandler)
	http.HandleFunc("/val", getHandler)
	
	log.Println("Server started on :8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

func setHandler(w http.ResponseWriter, r *http.Request) {
	val := []byte(r.URL.Path[5:])
	if err := sc.SetValue(w, val); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, "Cookie set with value: %s", val)
}

func getHandler(w http.ResponseWriter, r *http.Request) {
	val, err := sc.GetValue(nil, r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	fmt.Fprintf(w, "Cookie value: %s", val)
}

测试步骤:

  1. 创建目录并设置为工作目录:mkdir /tmp/sctest; cd /tmp/sctest
  2. 创建main.go文件并复制上述代码
  3. 创建go.mod文件:go mod init example.com
  4. 获取securecookie包:go get github.com/chmike/securecookie@v1.2.0
  5. 运行服务器:go run main.go
  6. 使用浏览器访问http://localhost:8080/set/someValue设置Cookie值
  7. 使用浏览器访问http://localhost:8080/val获取Cookie值

性能对比

指标 Chmike Gorilla
值长度 84 112
Set ns/op 2393 6309
Get ns/op 1515 5199
Set B/op 350 2994
Get B/op 192 2720
Set allocs/op 3 35
Get allocs/op 2 38

安全建议

  • 安全仅限Cookie内容,不能证明其他数据是由用户请求创建的
  • 考虑CSRF攻击风险,应为表单添加随机令牌验证
  • 对于REST API,客户端和服务器应共享密钥计算HMAC值验证请求

securecookie提供了一种高效安全的方式来处理Cookie,适合需要保护Cookie内容的Web应用场景。


更多关于golang高效安全的Cookie编码解码插件库securecookie的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang高效安全的Cookie编码解码插件库securecookie的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang SecureCookie 使用指南

SecureCookie 是一个用于 Go 语言的库,它提供了安全编码和解码 Cookie 的功能,能够防止客户端篡改 Cookie 值。下面我将详细介绍如何使用这个库。

安装

go get github.com/gorilla/securecookie

基本用法

package main

import (
	"fmt"
	"net/http"
	"github.com/gorilla/securecookie"
)

var (
	// HashKey 用于认证 (32或64字节)
	hashKey = securecookie.GenerateRandomKey(32)
	// BlockKey 用于加密 (16, 24或32字节)
	blockKey = securecookie.GenerateRandomKey(32)
	s = securecookie.New(hashKey, blockKey)
)

func main() {
	http.HandleFunc("/set", setCookieHandler)
	http.HandleFunc("/get", getCookieHandler)
	http.ListenAndServe(":8080", nil)
}

func setCookieHandler(w http.ResponseWriter, r *http.Request) {
	value := map[string]string{
		"foo": "bar",
	}
	
	if encoded, err := s.Encode("cookie-name", value); err == nil {
		cookie := &http.Cookie{
			Name:     "cookie-name",
			Value:    encoded,
			Path:     "/",
			Secure:   true,
			HttpOnly: true,
		}
		http.SetCookie(w, cookie)
	}
	fmt.Fprintln(w, "Cookie set!")
}

func getCookieHandler(w http.ResponseWriter, r *http.Request) {
	if cookie, err := r.Cookie("cookie-name"); err == nil {
		value := make(map[string]string)
		if err = s.Decode("cookie-name", cookie.Value, &value); err == nil {
			fmt.Fprintf(w, "Cookie value: %v", value)
		}
	} else {
		fmt.Fprintln(w, "Cookie not found")
	}
}

高级配置

自定义编码器

s := securecookie.New(hashKey, blockKey)
s.SetSerializer(securecookie.JSONEncoder{})

自定义哈希和加密算法

s := securecookie.New(hashKey, blockKey)
s.HashFunc(func() hash.Hash {
	return sha256.New()
})
s.BlockFunc(func(block []byte) (cipher.Block, error) {
	return aes.NewCipher(block)
})

设置最大年龄

s.MaxAge(86400) // 1天

安全最佳实践

  1. 密钥管理

    • 不要硬编码密钥
    • 使用环境变量或配置管理系统
    • 定期轮换密钥
  2. Cookie设置

    • 始终设置 Secure 标志(HTTPS)
    • 使用 HttpOnly 防止JavaScript访问
    • 设置适当的 PathDomain
  3. 错误处理

    • 不要忽略解码错误
    • 无效Cookie应被视为攻击尝试

完整示例

package main

import (
	"log"
	"net/http"
	"os"
	
	"github.com/gorilla/securecookie"
)

type User struct {
	Name  string
	Email string
}

var (
	hashKey  = []byte(os.Getenv("COOKIE_HASH_KEY"))
	blockKey = []byte(os.Getenv("COOKIE_BLOCK_KEY"))
	sc       = securecookie.New(hashKey, blockKey)
)

func main() {
	http.HandleFunc("/login", loginHandler)
	http.HandleFunc("/profile", profileHandler)
	
	log.Println("Starting server on :8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

func loginHandler(w http.ResponseWriter, r *http.Request) {
	user := User{
		Name:  "John Doe",
		Email: "john@example.com",
	}
	
	encoded, err := sc.Encode("user", user)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	
	cookie := &http.Cookie{
		Name:     "user",
		Value:    encoded,
		Path:     "/",
		MaxAge:   3600, // 1小时
		Secure:   true,
		HttpOnly: true,
		SameSite: http.SameSiteLaxMode,
	}
	
	http.SetCookie(w, cookie)
	w.Write([]byte("Login successful"))
}

func profileHandler(w http.ResponseWriter, r *http.Request) {
	cookie, err := r.Cookie("user")
	if err != nil {
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return
	}
	
	var user User
	if err = sc.Decode("user", cookie.Value, &user); err != nil {
		http.Error(w, "Invalid cookie", http.StatusBadRequest)
		return
	}
	
	w.Write([]byte("Welcome " + user.Name + " (" + user.Email + ")"))
}

注意事项

  1. 密钥长度必须正确:

    • HashKey: 32或64字节
    • BlockKey: 16(AES-128), 24(AES-192)或32(AES-256)字节
  2. 生产环境不要使用随机生成的密钥,应该使用固定的安全密钥

  3. 对于分布式系统,所有实例必须使用相同的密钥

SecureCookie 提供了一种简单而安全的方式来处理 Web 应用中的 Cookie,防止客户端篡改数据,是构建安全 Web 应用的重要工具之一。

回到顶部