You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

76 lines
2.9 KiB

package comm
import (
"strconv"
"testing"
"time"
)
func TestVerifyConsoleCall(t *testing.T) {
const key = "SzwdcXrtrmJMRZkZtQuzhAETOIJnFzMH"
const route = "user_login"
now := time.Unix(1_800_000_000, 0)
ts := strconv.FormatInt(now.Unix(), 10)
good := SignConsoleCall(key, ts, route, "")
// 翻转末位(末位本就可能是 '0',直接拼 "0" 会得到与原串相同的"篡改"签名,测试就成了假阳性)
tampered := good[:len(good)-1] + map[bool]string{true: "1", false: "0"}[good[len(good)-1] == '0']
if err := VerifyConsoleCall(key, ts, good, route, "", now); err != nil {
t.Fatalf("合法签名应通过: %v", err)
}
// 时钟小幅偏差仍应通过(两机时钟不会完全一致)
if err := VerifyConsoleCall(key, ts, good, route, "", now.Add(time.Minute)); err != nil {
t.Fatalf("1 分钟偏差应通过: %v", err)
}
cases := []struct {
name string
key, ts, sign, rt, arg string
at time.Time
}{
{"密钥不一致(两端 FIELD_ENCRYPT_KEY 不同)", "other-key", ts, good, route, "", now},
{"签名被篡改", key, ts, tampered, route, "", now},
{"签名绑定的是别的接口(防止换路由重放)", key, ts, SignConsoleCall(key, ts, "api_other", ""), route, "", now},
{"时间戳过期", key, ts, good, route, "", now.Add(10 * time.Minute)},
{"时间戳来自未来", key, ts, good, route, "", now.Add(-10 * time.Minute)},
{"缺时间戳", key, "", good, route, "", now},
{"缺签名", key, ts, "", route, "", now},
{"未配置密钥", "", ts, good, route, "", now},
{"时间戳非数字", key, "abc", good, route, "", now},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
if err := VerifyConsoleCall(c.key, c.ts, c.sign, c.rt, c.arg, c.at); err == nil {
t.Fatal("应当被拒绝")
}
})
}
}
// 路由白名单与实际注册的接口必须对得上,否则网关要么放行了不该放行的,要么把 console 挡在门外。
func TestConsoleOnlyRoutes(t *testing.T) {
if !IsConsoleOnlyRoute("api_reloadmoduleconfig") {
t.Fatal("重载接口必须是 console 专用路由(否则会裸奔在公网上)")
}
if !IsConsoleOnlyRoute("api_resetmoduleconfig") {
t.Fatal("重置接口必须是 console 专用路由")
}
if IsConsoleOnlyRoute("user_login") {
t.Fatal("普通用户接口不该被当作 console 专用路由")
}
}
// 参数(模块名)必须被签名绑定:否则截获一个"重置 email"的请求,改个头就能重置 wechatpay。
func TestSignBindsArg(t *testing.T) {
const key, route = "k", "api_resetmoduleconfig"
now := time.Unix(1_800_000_000, 0)
ts := strconv.FormatInt(now.Unix(), 10)
signEmail := SignConsoleCall(key, ts, route, "email")
if err := VerifyConsoleCall(key, ts, signEmail, route, "email", now); err != nil {
t.Fatalf("原参数应通过: %v", err)
}
if err := VerifyConsoleCall(key, ts, signEmail, route, "wechatpay", now); err == nil {
t.Fatal("参数被换成别的模块必须拒绝")
}
}