iT邦幫忙

2026 iThome 鐵人賽

DAY 29
0
Software Development

手刻 Redis:用 Go 從零打造高效能高併發的記憶體資料庫系列 第 29

Day 29:AUTH 安全密碼校驗與 CLIENT 連線管理機制實作

  • 分享至 

  • xImage
  •  

Redis 如果不設密碼就放上公網,大概不用多久就會被掃到,接著可能被拿去挖礦或塞奇怪的東西。所以密碼驗證(AUTH)這層不能省。

另外,為了方便運維查看現在有誰連著,還得加個連線管理(像是 CLIENT LIST, CLIENT KILL)。

今天就來幫這個專案補上基本的安全防線。


1. AUTH 安全密碼校驗

驗證設計與流程

  • 伺服器啟動時,若設置了密碼(例如透過配置或命令列引數傳入非空字串 password),則除了 AUTH 命令之外,其他所有接收到的命令都應被拒絕執行,並回傳 (error) NOAUTH Authentication required. 錯誤。
  • 客戶端連接後,必須先發送 AUTH <password>。伺服器比對正確後,將該連線的上下文 Client.Authenticated 標記為 true,隨後客戶端才能正常操作。

我把這個攔截放在 code/command/dispatcher.go 的核心分發邏輯裡:

實作的時候我踩了個坑,一開始把驗證邏輯寫在指令處理之後,結果發現密碼錯了指令還是跑完了,趕緊把它搬到最前面去攔截。

func (d *Dispatcher) Dispatch(client *Client, val resp.Value) resp.Value {
	// ... 解析指令名與引數 ...

	// 1. 密碼驗證校驗 (AUTH)
	if cmdName == "AUTH" {
		if d.requirePass == "" {
			return resp.NewError("ERR Client sent AUTH, but no password is set")
		}
		if len(args) != 1 {
			return resp.NewError("ERR wrong number of arguments for 'auth' command")
		}
		// 比對密碼
		if string(args[0]) == d.requirePass {
			client.Authenticated = true // 標記驗證成功
			return resp.NewSimpleString("OK")
		}
		return resp.NewError("ERR invalid password")
	}

	// 2. 若未通過驗證,拒絕其他所有指令
	if d.requirePass != "" && !client.Authenticated {
		return resp.NewError("NOAUTH Authentication required.")
	}

	// ... 正常執行其他命令 ...
}

2. CLIENT 連線管理

連線管理命令主要是讓我們看得到目前有哪些 client 還連著:

  • CLIENT LIST:回傳當前所有活躍客戶端連線的詳細資訊(如 IP、埠口、訂閱頻道數、驗證狀態等)。
  • CLIENT KILL <ip:port>:主動中斷指定的客戶端連線,釋放資源。

這類指令會碰到 server 連線狀態,所以我透過全域 ActiveServer 取得目前活躍連線,再做查詢或中斷:

實作設計:

// 於 commands.go 或 server 中實作客戶端連線查詢:
func clientListCommand(dbEngine *db.DB, client *Client, args [][]byte) resp.Value {
	// 利用 ActiveServer.conns 遍歷連線
	// 將每個連線的 RemoteAddr() 等metadata格式化為字串 Bulk 回傳
}

這種功能平常不一定會用到,但 debug 連線問題時會很方便。


跑起來看看

來看看我們的程式在壓測時,到底是哪邊在拖慢速度:

# 1. 開啟 pprof 收集,執行壓測
$ go test -cpuprofile cpu.prof -bench .

# 2. 進入 pprof 互動模式
$ go tool pprof cpu.prof
> top 10
# 預期回覆:
# Showing nodes accounting for 1.20s, 85.10% of 1.41s total
#       flat  flat%   sum%        cum   cum%
#      0.30s 21.28% 21.28%      0.35s 24.82%  syscall.syscall
#      0.25s 17.73% 39.01%      0.40s 28.37%  runtime.mallocgc
#      0.15s 10.64% 49.65%      0.15s 10.64%  sync.(*RWMutex).Lock
# ...

如果鎖競爭和系統呼叫佔比很高,後面就可以從分段鎖、批次寫回這些方向下手。


總結

今天補上 AUTHCLIENT 指令,至少不再是完全裸奔的服務。

明天就是最後一天了,打算補一些系統監控指令,再用 benchmark 壓一下,看看這 30 天寫出來的東西到底能跑多快。


上一篇
Day 28:實作主從複製 - 增量複製流傳播與寫指令廣播
下一篇
Day 30:鐵人賽結尾:系統監控命令、效能 Benchmark 與 30 天總結
系列文
手刻 Redis:用 Go 從零打造高效能高併發的記憶體資料庫30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言