编程 500行Go实现Web指纹识别引擎:HTTP Header+favicon Hash+HTML Title+Cookie组合投票

2026-07-29 13:08:26 +0800 CST views 8

500 行 Go 实现 Web 指纹识别引擎:Header + favicon Hash + Title + Cookie 组合投票

来源:微信公众号

为什么漏洞扫描器扫一下网站,就能识别出 Nginx、WordPress、OpenWrt,甚至 Jenkins、禅道?

底层并不是什么黑科技,而是几个最基础的步骤:规则积累 + 特征匹配。今天用 Go 一步步拆解 Web 指纹识别引擎的核心实现。

第一步:发起 HTTP 请求

Go 标准库已经帮我们做好了一切:

client := &http.Client{Timeout: 5 * time.Second}
resp, err := client.Get(target)
if err != nil {
    return
}
defer resp.Body.Close()

一次请求,就拿到了两样最重要的东西:HTTP HeaderHTML 内容——仅凭这两个信息,就已经能够识别大量 Web 产品。

第二步:HTTP Header 往往已暴露身份

很多服务器会主动声明自己的身份:

Header推断结果
Server: nginxNginx
Server: ApacheApache HTTP Server
X-Powered-By: PHP/8.2PHP 后端
Server: Jetty / Server: UndertowJava 技术栈

Go 获取 Header:

server := resp.Header.Get("Server")
powered := resp.Header.Get("X-Powered-By")

仅凭 Header,很多情况下就已经完成了一半的指纹识别。

第三步:favicon Hash 才是真正的"身份证"

Web 指纹识别里最经典的一招:favicon Hash

几乎每个网站都有 /favicon.ico,图片虽小,很多产品几十年不换。扫描器通常:

  1. 下载 favicon
  2. 计算 Hash
  3. 查询规则库
resp, _ := client.Get(target + "/favicon.ico")
body, _ := io.ReadAll(resp.Body)
sum := md5.Sum(body)
fmt.Printf("%x\n", sum)
// 例如:e3b0c44298fc1c149afbf4c8996fb924 → Jenkins

为什么不直接比较图片?因为 Hash 更快、更稳定。成熟产品一般使用 MurmurHash3 而非 MD5,以兼容 FOFA 等公开指纹体系。

第四步:HTML 页面里藏着大量信息

很多 CMS、博客平台、后台系统都喜欢在页面里留下"签名":

<meta name="generator" content="WordPress 6.8">
<meta name="generator" content="Discuz! X3.5">
<title>Jenkins</title>
<title>OpenWrt</title>

Go 读取页面并匹配关键字:

body, _ := io.ReadAll(resp.Body)
html := string(body)

if strings.Contains(html, "WordPress") {
    // ...
}

很多后台系统有固定的 Cookie 名称:

Cookie技术栈
JSESSIONIDJava
PHPSESSIDPHP
sysauthOpenWrt

Go 获取 Cookie:

for _, c := range resp.Cookies() {
    fmt.Println(c.Name)
}

第六步:URL 本身就是特征

很多系统有固定路径:

路径产品
/wp-adminWordPress
/login.actionJava 系统
/swagger-uiSpring Boot
/nacosNacos

Go 直接请求目标路径,返回 200 OK 即命中规则加分。

第七步:HTTPS 证书也会"泄密"

TLS 证书里经常暴露很多信息——有些公司甚至把产品名直接写进证书:

state := resp.TLS
if state != nil {
    for _, cert := range state.PeerCertificates {
        fmt.Println(cert.Subject.CommonName)
    }
}

多特征投票机制

真正的商业扫描器不会"Header 命中就结束",而是采用加权投票机制:

特征命中结果权重
HeaderNginx10
faviconOpenWrt15
TitleOpenWrt20
Cookiesysauth25
URL/cgi-bin/luci30

最终 OpenWrt 累计得分最高,可信度 99%。

一个简单的规则引擎

将规则抽象为结构体:

type Rule struct {
    Product string
    Header  string
    Title   string
    Cookie  string
    Favicon string
    URL     string
    Weight  int
}

扫描流程:

HTTP 请求 → 收集特征 → 匹配规则 → 累计权重 → 输出结果

比大量 if...else 更容易维护,也是很多商业扫描器的设计思路。

Go 为什么特别适合做指纹识别?

对于 1000 个网站的扫描:

  • 传统做法:1000 个线程,或复杂的异步框架
  • Go 做法
for _, url := range urls {
    go fingerprint(url)
}

每个目标一个 Goroutine,网络 IO 等待时 Runtime 自动调度其他任务。CPU 几乎一直在工作,而非等待网络。IO 密集型场景下,Go 优势非常明显。

总结

Web 指纹识别的核心只有一句话:尽可能多地收集目标特征,再综合判断

Header、Title、Cookie、favicon Hash、TLS 证书、URL 路径……每个特征单独看都可能不准确,但组合起来准确率会越来越高。

真正决定识别效果的,不是语言,而是规则库的质量和持续更新。写几百行 Go 代码不难,难的是维护一套与日俱进的规则体系。

推荐文章

H5抖音商城小黄车购物系统
2024-11-19 08:04:29 +0800 CST
Requests库详细介绍
2024-11-18 05:53:37 +0800 CST
Go 语言实现 API 限流的最佳实践
2024-11-19 01:51:21 +0800 CST
Gai:AI 原生的 Go Web 全栈框架
2026-05-21 16:19:43 +0800 CST
如何在Rust中使用UUID?
2024-11-19 06:10:59 +0800 CST
JavaScript中设置器和获取器
2024-11-17 19:54:27 +0800 CST
php curl并发代码
2024-11-18 01:45:03 +0800 CST
程序员茄子在线接单