java 模拟chrome指纹 处理tls extension顺序

1.前言

上篇提到了 tls指纹 ja4和ja3指纹已经一致,但ja3_text的顺序并非一致,为进一步优化指纹,需要保证tls extension顺序一致性。

  • 拉取bc源码
  • bc环境,修改bc源码,打包
  • 修改tlsClien实现类

bc gradle打包限制太多,具体打包问题问ai即可解决

2.实现

首先看tlsClien实现类

我们继承了 DefaultTlsClient ,实现getClientExtensions,此方法返回为hashtable,hashtable的存取顺序并非统一,所以我们需要更换为LinkedMap

2.1 找到bc类的具体实现

bash 复制代码
AbstractTlsClient


修改为这样,底下的实现部分随之修改

2.2 hashtable更换

将编译报错的地方一一修改,这里推荐 ctrl+shift+r 替换所有

bash 复制代码
HashTableclient Extensions

bash 复制代码
LinkedHashMap Extensions

然后再一一修改,大概几十个文件,改一个小时左右

2.3 tls请求顺序固定

ctrl+n 找到类TlsProtocol

搜索 writeExtensionsData并修改

bash 复制代码
    protected static void writeExtensionsData(LinkedHashMap extensions, int bindersSize, ByteArrayOutputStream buf)
        throws IOException
    {
        /*
         * NOTE: There are reports of servers that don't accept a zero-length extension as the last
         * one, so we write out any zero-length ones first as a best-effort workaround.
         */
//        writeSelectedExtensions(buf, extensions, true);
//        writeSelectedExtensions(buf, extensions, false);
        writeSelectedExtensions(buf, extensions);
        writePreSharedKeyExtension(buf, extensions, bindersSize);
    }

writeSelectedExtensions方法修改

bash 复制代码
   protected static void writeSelectedExtensions(OutputStream output, LinkedHashMap extensions)
        throws IOException
    {
        Iterator keys = extensions.keySet().iterator();
        while (keys.hasNext())
        {
            Integer key = (Integer)keys.next();
            int extension_type = key.intValue();

            // NOTE: Must be last; handled by 'writePreSharedKeyExtension'
            if (ExtensionType.pre_shared_key == extension_type)
            {
                continue;
            }

            byte[] extension_data = (byte[])extensions.get(key);

            TlsUtils.checkUint16(extension_type);
            TlsUtils.writeUint16(extension_type, output);
            TlsUtils.writeOpaque16(extension_data, output);
        }
    }

源方法是过滤空val发一次,再过滤非空val发一次,我们直接一次发送完,让其顺序一致

2.4 BcTlsClient实现修改

此拓展为简陋版本,非chrome实际扩展,实际扩展自己可以自己找找

bash 复制代码
 @Override
    public LinkedHashMap<Integer, byte[]> getClientExtensions() throws IOException {
        LinkedHashMap ext = TlsExtensionsUtils.ensureExtensionsInitialised(super.getClientExtensions());
        ext.clear();
        // ---------- 1) GREASE extension (43690) ----------
        ext.put(6682, new byte[]{0x00}); // 占位:GREASE 自定义内容(Chrome 只是随便填)


        // ---------- 17) server_name (0) ----------
        Vector<ServerName> serverNames = new Vector<>();
        serverNames.add(new ServerName(NameType.host_name, host.getBytes()));
        TlsExtensionsUtils.addServerNameExtensionClient(ext, serverNames);

        // ---------- 9) application_settings (17613) ----------
        // 非标准扩展:这里用简单格式: [uint8 num_protocols][uint8 len][bytes protocol]...
        {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            TlsUtils.writeUint8(1, bos);            // 1 protocol
            byte[] p = "h2".getBytes();
            TlsUtils.writeUint8(p.length, bos);     // protocol length
            bos.write(p, 0, p.length);
            ext.put(17613, bos.toByteArray());
        }

        ext.put(43690, new byte[]{0x00}); // 占位:GREASE 自定义内容(Chrome 只是随便填)

        return ext;
    }

bc打包,整到项目里面

到此完毕

2.5 请求tls包对比

右边为chrome指纹,左边java指纹,基本上一致,中间4个指纹是会随请求改变的

akamai_hash未公开算法,不做研究,且java极难实现

3. notice

感谢chatgpt,bc分析很好用

依赖补充

bash 复制代码
  <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk18on</artifactId>
            <!-- 请查看最新版本 -->
            <version>1.83</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/libs/bcprov-jdk18on-1.83.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bctls-jdk18on</artifactId>
            <version>1.83</version> <!-- 替换为最新版本 -->
            <scope>system</scope>
            <systemPath>${project.basedir}/libs/bctls-jdk18on-1.83.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcutil-jdk18on</artifactId>
            <version>1.83</version> <!-- 替换为最新版本 -->
            <scope>system</scope>
            <systemPath>${project.basedir}/libs/bcutil-jdk18on-1.83.jar</systemPath>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty.http2</groupId>
            <artifactId>http2-common</artifactId>
            <version>11.0.21</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty.http2</groupId>
            <artifactId>http2-hpack</artifactId>
            <version>11.0.21</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-util</artifactId>
            <version>11.0.21</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-http</artifactId>
            <version>11.0.21</version>
        </dependency>
相关推荐
Chester_19996 小时前
CSP202203C.计算资源调度器
开发语言·数据结构·c++·蓝桥杯
EXI-小洲7 小时前
Java 操作 Word:字符串替换、图片插入、动态生成表格与API接口下载
java·开发语言·spring boot·word
会周易的程序员8 小时前
给 PLC 写一个字节码虚拟机:STVM 虚拟机架构设计
开发语言·c++·虚拟机·软plc·iec61131·stvm
机器视觉知识推荐、就业指导8 小时前
为什么老说“纯 Qt 没啥就业市场”?
开发语言·qt
telepan8 小时前
Qt 开发避坑与性能指南:如何优雅、安全地定义全局常量字符串?
开发语言·qt
m0_695251498 小时前
Qt MaintenanceTool 使用国内镜像加速下载(超详细教程)
开发语言·qt
2601_961901708 小时前
SpringBoot使用Nacos进行application.yml配置管理
java·spring boot·spring
何以解忧,唯有..9 小时前
LangChain 工具调用(Tool Calling)实战指南
java·前端·langchain
大衛說9 小时前
《Python 从入门到精通》系列总览与学习路线
开发语言·python·学习
QQ_21696290969 小时前
【源码编号:project79475】SpringBoot校内二手交易平台:商品发布、分类检索、留言交流、订单管理全流程实战
java·spring boot·后端