这是关于网络指纹识别的两部分系列的第二部分

上一部分我介绍了有关TLS 指纹识别方法(以及在不同客户端的指纹有何区别):

https://mp.weixin.qq.com/s/BvotXrFXwYvGWpqHKoj3uQ

HTTP/2 指纹识别

和Tls指纹类似也是一种 Web 服务器可以依赖指纹来识别哪个客户端。

例如,它可以识别浏览器类型和版本,或者是否使用了脚本(你是真实浏览器啊还是ScriptBoy?)。

该方法依赖于 HTTP/2 协议的内部结构,与其更简单的前身 HTTP/1.1 相比,这些内部结构鲜为人知。

在这篇文章中,我将首先简要介绍 HTTP/2协议,然后详细介绍我们可以协议的哪些参数来识别你究竟谁(what are you)!

与HTTP/1.1相比

使用HTTP/1.1协议,客户端向服务器发送文本请求(通常使用 TLS 加密)默认情况下,Chrome 的请求如下所示:


GET / HTTP/1.1
Host: www.wikipedia.org sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="101", "Google Chrome";v="101"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9

User-Agent包含客户端的确切版本,虽然可用于识别客户端。但是很容易被任何 http 库或命令行工具伪造(地球人都知道)!

HTTP/2 简介

HTTP/2 是 HTTP 协议的主要修订版,从 2015 年左右开始出现。现在大约一半的网站使用 HTTP/2

基本上所有流行的网站都默认使用它!

如何看服务端使用的是否是http2协议呢?

在chrome上看是这样的

在Firefox上看是这样的

HTTP/2 的主要目标是提高性能
  • 多路复用(Multiplexing ) - 多个请求和响应可以同时共享同一个 TCP 连接,从而减少了获取具有大量资源(图像、脚本等)的站点的时间。
  • 优先级(PRIORITY) - HTTP/2 支持对某些请求和响应进行优先级排序。
  • 服务器推送(Server push) - 在 HTTP/2 中,服务器可以在客户端请求资源之前将资源发送给客户端。

然而,HTTP 协议的应用程序语义没有改变:它仍然由熟悉的请求/响应模型组成,包括 URI、HTTP 方法、HTTP 标头和状态码。

Frames and Streams

HTTP/2 是一种二进制协议,与文本 HTTP/1.1 不同。HTTP/2 中的消息由帧组成,有十种不同用途的帧。帧始终是流的一部分。

Stream都是有编号的,从0开始

如上图:编号为0的Stream包含如下

  • SETTINGS是客户端发送的第一帧,包含 HTTP/2 的特定配置,
  • WINDOW_UPDATE- 增加接收器的窗口大小,下面会讲到

然后是编号开始递增,代表了客户端给服务端发送的实际请求,如上图为1的Stream:

  • HEADERS 包含 URI、HTTP 方法和客户端的 HTTP 头
  • DATA 包含来请求的资源数据以及服务器的响应

使用 HTTP/2 进行客户端指纹识别

研究http2协议的工具

这里推荐使用nghttpd,它可以很方便的创建一个http2协议的webserver。

最关键的是,让客户端请求的时候它能够直观的把每一帧都给打印出来(下面会给大家演示)

我将它安装在wsl的ubuntu机器上,还得自建一个证书,这里我遇到了一点坑,

避坑指南请看我写的(wsl创建证书让chrome浏览器识别):

下面就是如何使用nghttpd跑h2协议server

我这里分别使用如下客户端来测试

  • Chrome浏览器
  • Firefox浏览器
  • CURL
  • Python脚本

1. SETTINGS

上面介绍到这是客户端发送的第一帧,里面有一些特殊配置

Chrome

recv SETTINGS frame <length=24, flags=0x00, stream_id=0>
[SETTINGS_HEADER_TABLE_SIZE(0x01):65536]
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):1000]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):6291456]
[SETTINGS_MAX_HEADER_LIST_SIZE(0x06):262144]
Firefox

recv SETTINGS frame <length=18, flags=0x00, stream_id=0>
[SETTINGS_HEADER_TABLE_SIZE(0x01):65536]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):131072]
[SETTINGS_MAX_FRAME_SIZE(0x05):16384]
CURL

recv SETTINGS frame <length=18, flags=0x00, stream_id=0>
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):1073741824]
[SETTINGS_ENABLE_PUSH(0x02):0]
PYTHON

recv SETTINGS frame <length=36, flags=0x00, stream_id=0>
[SETTINGS_HEADER_TABLE_SIZE(0x01):4096]
[SETTINGS_ENABLE_PUSH(0x02):0]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[SETTINGS_MAX_FRAME_SIZE(0x05):16384]
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_MAX_HEADER_LIST_SIZE(0x06):65536]

很明显,根据测试,在SETTINGS Frame帧里面配置,

不同的客户端设置的种类和值都是不同的,这使得很容易区分是否是浏览器,

而且这个配置不容易控制,可以用于指纹识别!

WINDOW_UPDATE

HTTP/2 实现了一种流控制机制。

流量控制为接收方提供了在每个流的基础上调节流量的机制。

使用WINDOW_UPDATE大小来实现的

默认窗口大小由SETTINGS帧里面的 SETTINGS_INITIAL_WINDOW_SIZE中的值控制,

参考上方测试,可以看到 Chrome 使用 6MB (6291456) 而 Firefox 使用 128KB (131072)

当客户端接收数据时,它可以使用WINDOW_UPDATE框架来调整窗口大小,从而增加其窗口大小。

Chrome
recv WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
(window_size_increment=15663105)

Chrome 实际上将连接级窗口大小增加到 15MB (15663105+65535=15MB)

Firefox
recv WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
(window_size_increment=12517377)

Firefox 会将其增加到 12MB

CURL
recv WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
(window_size_increment=1073676289)

curl使用 32MB

参考:https://github.com/curl/curl/blob/10cd69623a544c83bae6d90acdf141981ae53174/lib/http2.c#L62

PYTHON
recv WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
(window_size_increment=16777216)

PYTHON 会将其增加到 16MB

所以我们也可以使用该参数用于指纹识别!

HEADERS

这个有点意思了

从广义上讲,HEADERS 包含了 HTTP/1.1 的所有功能,包含了

URI、方法(GET/POST/等)和客户端的头等!

下面的几个伪标头的顺序对于每个客户端是不同的。

  • :method
  • :authority
  • :scheme
  • :path

我们来测试一下

Chrome

顺序是:

m,a,s,p

Firefox

顺序是:

m,p,a,s

CURL

顺序是:

m,p,s,a

Python

顺序是:

m,a,s,p

这个看似很小的差异,也可以用于指纹识别

HTTP/2 指纹识别在哪里使用?

它用于与TLS 指纹识别类似的目的:比如反 DDOS 和反脚本等自动爬虫(提高门槛),只允许真实浏览器等。

如何让你的server具有提取客户端HTTP2指纹的能力

ja3是tls指纹的标准,wiresharp也默认带有

搞http2指纹的目前市面上还没有标准,

我开源了一款提取tls&http2指纹的中间件(面向aspnetcore的)

https://github.com/yuzd/ja3-csharp

在线测试:

https://kawayiyi.com/tls


{
"tlsVersion": "Tls12",
"tcpConnectionId": "0HMKCUARI97OU",
"tlsHashOrigin": "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513-21,29-23-24,0",
"tlsHashMd5": "cd08e31494f9531f560d64c695473da9",
"cipherList": [
"TLS_AES_128_GCM_SHA256",
"TLS_AES_256_GCM_SHA384",
"TLS_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_RSA_WITH_AES_128_GCM_SHA256",
"TLS_RSA_WITH_AES_256_GCM_SHA384",
"TLS_RSA_WITH_AES_128_CBC_SHA",
"TLS_RSA_WITH_AES_256_CBC_SHA"
],
"extentions": [
"server_name",
"extended_master_secret",
"renegotiation_info",
"supported_groups",
"ec_point_formats",
"session_ticket",
"application_layer_protocol_negotiation",
"status_request",
"signature_algorithms",
"signed_certificate_timestamp",
"key_share",
"psk_key_exchange_modes",
"supported_versions",
"compress_certificate",
"extensionApplicationSettings",
"padding"
],
"supportedgroups": [
"X25519",
"CurveP256",
"CurveP384"
],
"ecPointFormats": [
"uncompressed"
],
"proto": "HTTP/2",
"h2": {
"SETTINGS": {
"1": "65536",
"3": "1000",
"4": "6291456",
"6": "262144"
},
"WINDOW_UPDATE": "15663105"
}
}

如何过http2指纹呢?

知道了原理,还不好过吗

总结

指纹识别在整个网络中变得非常普遍,Http2的指纹相对来说不为人知,但是并不新鲜

比如这篇论文:

https://www.blackhat.com/docs/eu-17/materials/eu-17-Shuster-Passive-Fingerprinting-Of-HTTP2-Clients-wp.pdf

详细介绍了一项具有类似结论的研究

本文参考了@lwthiker大神的研究,加上了自己的实践(解析http2协议),感谢他的指点

HTTP2指纹识别(一种相对不为人知的网络指纹识别方法)的更多相关文章

  1. 利用神经网络进行网络流量识别——特征提取的方法是(1)直接原始报文提取前24字节,24个报文组成596像素图像CNN识别;或者直接去掉header后payload的前1024字节(2)传输报文的大小分布特征;也有加入时序结合LSTM后的CNN综合模型

    国外的文献汇总: <Network Traffic Classification via Neural Networks>使用的是全连接网络,传统机器学习特征工程的技术.top10特征如下 ...

  2. 不为人知的网络编程(八):从数据传输层深度解密HTTP

    1.引言 在文章<理论联系实际:Wireshark抓包分析TCP 3次握手.4次挥手过程>中,我们学会了用wireshark来分析TCP的“三次握手,四次挥手”,非常好用.这就是传说中的锤 ...

  3. PatentTips -- 一种在CoAP网络中注册的方法及装置

    技术领域 [0001] 本发明涉及一种在CoAP网络中注册的方法及装置,属于网络通信技术领域. 背景技术 [0002] (Internet of Things,物联网)作为新一代的信息技术,越来越受到 ...

  4. 不为人知的网络编程(九):理论联系实际,全方位深入理解DNS

    本文原作者:selfboot,博客地址:selfboot.cn,Github地址:github.com/selfboot,感谢原作者的技术分享. 1.引言 对于 DNS(Domain Name Sys ...

  5. larbin是一种开源的网络爬虫/网络蜘

    larbin是一种开源的网络爬虫/网络蜘蛛,由法国的年轻人 Sébastien Ailleret独立开发.larbin目的是能够跟踪页面的url进行扩展的抓取,最后为搜索引擎提供广泛的数据来源.Lar ...

  6. PHP几种抓取网络数据的常见方法

    //本小节的名称为 fsockopen,curl与file_get_contents,具体是探讨这三种方式进行网络数据输入输出的一些汇总.关于 fsockopen 前面已经谈了不少,下面开始转入其它. ...

  7. 微软引入了两种新的网络过滤系统,WFP和NDISfilter

    Windows 8是微软公司推出的最新的客户端OS,内部名称Windows NT 80.相对于Windows NT 5.x,其网络结构变化非常大,原有的TDI,NDIS系统挂接方法不再适用.在Wind ...

  8. opencv —— 同时识别三种颜色

    要点: 1.识别一种颜色 minH = ; //色相 maxH = ; minS = ; //饱和度 maxS = ; minV = ; // inRange(原图像, 最小值的范围, 最大值的范围, ...

  9. 【Android】一种提高Android应用进程存活率新方法

    [Android]一种提高Android应用进程存活率新方法 SkySeraph Jun. 19st 2016 Email:skyseraph00@163.com 更多精彩请直接访问SkySeraph ...

随机推荐

  1. Java中时间方法大全01(持续更新)

    下面这些方法都可以封装到一个工具类中 /** * 获取当前时间的时间戳 */ public static int getCurrentTimeIntValue() { return (int) (Sy ...

  2. ASPNET Core笔试题

    1.如何在ASP.NET Core中激活Session功能? 首先要添加session包. 其次要在configservice方法里面添加session.然后又在configure方法里面调用 use ...

  3. Android Studio 的初次使用

    记录我第一次使用Android Studio时遇到的问题以及一些简单的笔记. 我所使用的是Android Studio 2.2版本 遇到的问题 创建一个Hello World!项目无疑是相当简单的,我 ...

  4. multiset 用法复习

    前言 看题解上有 \(\text{multiset}\) 然后发现没脑子的我又忘了... 正文 \(\text{multiset}\) 可以看成一个序列,插入一个数,删除一个数都能够在 \(O(\lo ...

  5. 5-7 分页查询PageHelper

    1. PageHelper实现分页查询 Day08 1.1 PH作用: PageHelper框架可以实现我们提供页码和每页条数, 自动实现分页效果,收集分页信息 1.2 PH原理: PageHelpe ...

  6. Running Median_via牛客网

    题目 链接:https://ac.nowcoder.com/acm/contest/28886/1002 来源:牛客网 时间限制:C/C++ 5秒,其他语言10秒 空间限制:C/C++ 65536K, ...

  7. Stream流中的常用方法foeEach和Stream流中的常用方法filter

    延迟方法:返回值类型仍然是Stream接口自身类型的方法,因此支持链式调用.(除了中介方法外,其余方法均为延迟方法) 终结方法:返回值类型不再是Stream接口自身类型的方法,因此不再支持类似Stri ...

  8. axios&spring前后端分离传参规范总结

    前后端分离开发的场景下,开发人员的工作内容更加专注与专业,但是也产生了一些额外的沟通成本.比如:本文中为大家说明的前后端参数传递与接受方法.本文主要是面对前端使用axios,后端使用Spring进行参 ...

  9. 鸟枪换炮,利用python3对球员做大数据降维(因子分析得分),为C罗找到合格僚机

    鸟枪换炮,利用python3对球员做大数据降维(因子分析得分),为C罗找到合格僚机 原文转载自「刘悦的技术博客」https://v3u.cn/a_id_176 众所周知,尤文图斯需要一座欧冠奖杯,C罗 ...

  10. PostgreSQL 备份

    # WAL日志: # 我们对数据库的增删改查创建之前先是将sql语句记录在WAL日志中, # 只有日志记录刷新到磁盘后,才能写入数据库文件. # 遵从这个过程,不需要在每个事务提交时都刷新数据页到数据 ...