Jacky's blog
首页
  • 学习笔记

    • web
    • android
    • iOS
    • vue
  • 分类
  • 标签
  • 归档
收藏
  • tool
  • algo
  • python
  • java
  • server
  • growth
  • frida
  • blog
  • SP
  • more
GitHub (opens new window)

Jack Yang

编程; 随笔
首页
  • 学习笔记

    • web
    • android
    • iOS
    • vue
  • 分类
  • 标签
  • 归档
收藏
  • tool
  • algo
  • python
  • java
  • server
  • growth
  • frida
  • blog
  • SP
  • more
GitHub (opens new window)
  • shell

  • tool

  • 网络

    • network category
    • http base
    • network concept
    • https
    • 网络高频问题
    • 网络安全
    • java http sign snip
      • case
      • 实现分析
        • 1.时间戳
        • 2.签名内容集合
        • 3.SHA-256 哈希
        • 4.HMAC 签名
        • 5.RSA 加密
        • 6.组合签名和加密内容
      • 破解评估
    • 软路由
    • DHCP
    • ACME
    • 闲置android手机充当软路由
    • 代理检测方式及绕过方式
  • algo

  • compute_base

  • blog

  • growth

  • java

  • C&C++

  • ai

  • secure

  • cms

  • english

  • 生活

  • 金融学

  • more

  • other
  • 网络
Jacky
2024-05-18
目录

java http sign snip

关联文章 加解密技术

# case

private static String sign(String urlString, HttpRequestClient.Method method, byte[] body) {
    Map.Entry<String, String> randomValue = pubicKeyEntries.get(generator.nextInt(pubicKeyEntries.size()));
    String time = String.valueOf((System.currentTimeMillis() - InnerLogicManager.get().getServerTimestampDelta()) / 1000);

    final List<String> contentOfSign = new ArrayList<>(6);
    contentOfSign.add(time);
    contentOfSign.add(method.name());
    try {
        URL url = new URL(urlString);
        String path = url.getPath();
        if (path == null) {
            contentOfSign.add("");
        } else {
            contentOfSign.add(path);
        }
        String query = url.getQuery();
        if (query == null) {
            contentOfSign.add("");
        } else {
            contentOfSign.add(query);
        }
    } catch (MalformedURLException e) {
        Logger.e(e);
    }
    try {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hash = digest.digest(body);
        String bodySign = bytesToHex(hash);
        contentOfSign.add(bodySign);
    } catch (NoSuchAlgorithmException e) {
        Logger.e(e);
    }
    String sign = DeviceDependence.current.getDeviceInject().hmac(key, Strings.joinStrings(contentOfSign, '\n'));

    final List<String> content = new ArrayList<>();
    content.add("version=" + version);
    content.add("type=0");      // type = 0 , 只签名不加密, 防止非法调用接口
    content.add("key=" + Base64.encodeToString(key.getBytes(), Base64.DEFAULT));
    content.add("time=" + time);

    String encryptedContent = DeviceDependence.current.getDeviceInject().rsaEncode(
        Strings.joinStrings(content, ';'), randomValue.getValue());

    return "key=" + randomValue.getKey() + ";secret=" + encryptedContent + ";signature=" + sign;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

这个 sign 方法通过多种方式来保证安全性,确保请求的完整性、身份验证和防止重放攻击。以下是具体的安全性保证措施:

最终返回的字符串包括随机选择的公钥标识符、加密的内容和 HMAC 签名。这种组合方式确保了请求的完整性、身份验证以及数据的加密保护

  • 完整性: SHA-256 哈希值和 HMAC 签名保证请求数据的完整性,防止数据被篡改
  • 身份验证: HMAC 签名确保只有持有正确密钥的客户端才能生成合法签名,防止未授权的请求
  • 防重放攻击: 时间戳的使用防止请求被重放,确保每次请求都是唯一的
  • 加密保护: RSA 加密保护敏感信息在传输过程中的机密性,防止数据泄露

这些措施共同确保了请求在传输过程中的安全性,防止各种攻击和数据泄露

# 实现分析

# 1.时间戳

String time = String.valueOf((System.currentTimeMillis() - InnerLogicManager.get().getServerTimestampDelta()) / 1000);
1

使用当前时间戳(减去服务器时间差)作为签名的一部分,可以防止重放攻击,因为签名包含了特定时间的信息,每次请求的时间戳都是唯一的

# 2.签名内容集合

final List<String> contentOfSign = new ArrayList<>(6);
contentOfSign.add(time);
contentOfSign.add(method.name());
contentOfSign.add(path);
contentOfSign.add(query);
contentOfSign.add(bodySign);
1
2
3
4
5
6

将时间戳、HTTP 方法、URL 路径、查询参数和请求体的哈希值(SHA-256)组成一个集合,用于生成签名。这确保了请求的完整性,防止请求在传输过程中被篡改

# 3.SHA-256 哈希

MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(body);
String bodySign = bytesToHex(hash);
contentOfSign.add(bodySign);
1
2
3
4

计算请求体的 SHA-256 哈希值,并将其加入签名内容集合中,确保请求体的完整性和唯一性

# 4.HMAC 签名

String sign = DeviceDependence.current.getDeviceInject().hmac(key, Strings.joinStrings(contentOfSign, '\n'));
1

使用 HMAC(基于密钥的哈希消息认证码)算法对签名内容集合进行签名,确保签名的真实性和完整性。只有持有正确密钥的双方才能生成和验证此签名

# 5.RSA 加密

String encryptedContent = DeviceDependence.current.getDeviceInject().rsaEncode(
Strings.joinStrings(content, ';'), randomValue.getValue());
1
2

将请求中的关键信息(版本、类型、密钥、时间戳)进行拼接后,用 RSA 公钥加密。RSA 加密是一种非对称加密算法,确保数据在传输过程中不被第三方窃取和篡改

# 6.组合签名和加密内容

return "key=" + randomValue.getKey() + ";secret=" + encryptedContent + ";signature=" + sign;
1

# 破解评估

评估上述 API 在客户端中的破解难度涉及考虑攻击者可能使用的不同技术和方法。以下是对可能的攻击途径和破解难度的详细评估:

  1. 时间戳防重放攻击:
  • 攻击难度: 中等
  • 分析: 攻击者需要获取有效的时间戳并在短时间内重放请求。尽管时间戳能防止简单的重放攻击,但如果攻击者能截获并迅速重放请求,仍可能成功。因此,时间戳的保护强度在于其有效期的短暂性
  1. SHA-256 哈希值计算:
  • 攻击难度: 低
  • 分析:SHA-256 哈希函数是公开的,攻击者可以轻松计算任何数据的 SHA-256 哈希值。然而,这部分并不会直接暴露密钥信息,主要用于确保数据完整性
  1. HMAC 签名:
  • 攻击难度: 高
  • 分析: HMAC 签名需要一个秘密密钥。假设密钥存储在客户端且保护得当(如通过硬编码或混淆),攻击者需要获取该密钥才能生成有效的签名。提取密钥通常需要逆向工程客户端代码或从设备存储中读取,这些操作较为复杂
  1. RSA 加密:
  • 攻击难度: 高
  • 分析:RSA 加密使用公钥加密敏感信息。即使攻击者能截获加密的数据,也难以解密,除非获取私钥。私钥通常不会存储在客户端,而是保存在服务器端,因此攻击者难以直接破解加密数据
  1. 整体破解难度:
  • 攻击难度: 中到高
  • 分析: 攻击者需要通过多种复杂技术手段,包括逆向工程、内存分析、代码注入等,才能破解整个签名过程。以下是一些具体的破解方法及其难度:
    • 逆向工程和代码注入: 攻击者可能尝试逆向工程客户端应用,以理解并提取密钥和签名算法。这通常需要熟练的逆向工程技术和工具
    • 内存分析: 攻击者可以使用调试工具或内存分析工具(如 Frida)动态分析应用运行时的内存,捕获密钥和其他敏感信息。这需要高级技术和深入的应用知识
    • 代码混淆和反混淆: 如果客户端代码经过混淆处理,破解难度将大幅增加。然而,经验丰富的攻击者仍可能通过反混淆和动态调试破解代码
总结:

综合考虑上述保护措施和可能的攻击方法,该 API 在客户端的破解难度总体较高。虽然部分防护机制(如 SHA-256 哈希和时间戳)较易绕过,但核心的 HMAC 签名和 RSA 加密有效地提升了破解难度。为了进一步提高安全性,可以采用以下措施:

  • 使用代码混淆工具保护客户端代码,增加逆向工程难度
  • 在客户端尽量少存储或传递敏感信息,减少被攻击者提取的可能性
  • 实现动态密钥管理机制,定期更新密钥,降低密钥泄露后的风险

即使如此,再强的客户端安全措施也无法完全避免被攻破的可能性,因此,服务器端的安全防护同样至关重要

#security#网络
上次更新: 2025/10/11, 09:25:12
网络安全
软路由

← 网络安全 软路由→

最近更新
01
npx 使用指南
10-12
02
cursor
09-28
03
inspect
07-20
更多文章>
Theme by Vdoing | Copyright © 2019-2025 Jacky | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式