旺仔小糖

captcha.VerifyString验证逻辑 7 months ago

go
2480个字符
共有56人围观

函数签名

根据 dchest/captcha源码VerifyString 的定义如下:

func VerifyString(id string, digits string) bool
  • id: 验证码的唯一标识符,用于从内部存储中检索对应的验证码答案。
  • digits: 用户输入的验证码字符串(通常是一串数字)。

返回值是一个布尔值,表示用户输入是否与存储的验证码答案匹配。


逻辑分析

VerifyString 的核心逻辑可以分解为以下步骤:

  1. 输入清洗

    • 函数首先对用户输入的 digits 字符串进行处理,去除其中的空格和逗号。
    • 这是为了提高容错性,允许用户输入类似 "1 2 3 4""1,2,3,4" 这样的格式,而不会直接失败。
    • 处理后,digits 只保留数字字符。如果字符串中包含除数字、空格、逗号外的其他字符,函数会直接返回 false
  2. 从存储中获取真实答案

    • 使用 id 从全局存储(globalStore)中检索对应的验证码答案。
    • globalStore.Get(id, true) 被调用,其中 true 表示在获取答案后立即从存储中删除该验证码(确保验证码是一次性的)。
    • 如果 id 不存在(即没有找到对应的验证码),返回 nil,函数会返回 false
  3. 答案比较

    • 将清洗后的 digits(转换为字节切片)与存储中的真实答案(也是字节切片)进行比较。
    • 使用 bytes.Equal 函数逐字节比较两者是否完全一致。
    • 如果一致,返回 true;否则,返回 false
  4. 一次性验证

    • 如前所述,调用 globalStore.Get(id, true) 后,无论验证结果如何,该验证码都会从存储中被删除。这确保了验证码只能被验证一次,防止重放攻击。

源码实现

以下是 VerifyString 的简化源码(基于 dchest/captcha 的实现):

func VerifyString(id string, digits string) bool {
    if digits == "" {
        return false
    }
    // 去除空格和逗号
    cleaned := strings.ReplaceAll(digits, " ", "")
    cleaned = strings.ReplaceAll(cleaned, ",", "")
    // 检查是否只包含数字
    for _, c := range cleaned {
        if c < '0' || c > '9' {
            return false
        }
    }
    // 从存储中获取真实答案并删除
    realDigits := globalStore.Get(id, true)
    if realDigits == nil {
        return false
    }
    // 比较答案
    return bytes.Equal([]byte(cleaned), realDigits)
}

逻辑特点

  1. 简单直接

    • VerifyString 不涉及复杂的加密或哈希,直接比较字节内容,依赖于存储中的原始答案。
  2. 输入容错

    • 允许空格和逗号,但严格要求只包含数字字符,增加了用户输入的灵活性,同时保持安全性。
  3. 一次性使用

    • 通过删除机制确保验证码不能重复使用,符合 CAPTCHA 的典型设计目标。
  4. 依赖存储

    • 函数的正确性依赖于 globalStore 的状态。如果存储中没有对应的 id,验证必然失败。

使用示例

假设你生成了一个验证码,ID 为 "abc123",答案为 "1234"

import "github.com/dchest/captcha"

func main() {
    // 假设已经生成了验证码 "1234",ID 为 "abc123"
    id := "abc123"
    
    // 用户输入正确的情况
    result := captcha.VerifyString(id, "1234")  // 返回 true
    println(result)

    // 用户输入包含空格
    result = captcha.VerifyString(id, "1 2 3 4")  // 返回 false(因已被删除)
    println(result)

    // 用户输入错误
    result = captcha.VerifyString(id, "5678")  // 返回 false(ID已失效)
    println(result)
}

注意事项

  • 安全性dchest/captcha 的文档中提到,这种验证码可能被高级 OCR(光学字符识别)算法破解,因此不建议用于高安全需求的场景。
  • 存储管理:默认使用内存存储(globalStore),有过期时间(默认 10 分钟)和垃圾回收机制。如果需要持久化,可以通过实现 Store 接口自定义存储。