脆弱的加密实践如何威胁银行业软件安全

本文深入探讨了银行业应用程序中常见的加密陷阱,包括硬编码密钥、使用弱算法、不安全的随机数生成以及校验和缺乏盐值。文章分析了这些缺陷带来的安全风险,并提出了结合RSA与AES、使用安全随机数生成器及加盐哈希等最佳实践来加固金融软件的安全性。

在当今数字时代,金融机构严重依赖加密技术来保护其银行应用程序中的敏感数据。然而,尽管密码学扮演着关键角色,许多实现却存在根本性缺陷,造成了虚假的安全感。对密码学原理的误解,加上为快速满足安全标准所做的努力,常常导致使用弱或过时的算法、不当的密钥管理以及有缺陷的加密协议。这些常见错误使银行客户易受攻击,导致数据泄露和财务损失等严重后果。对于开发者而言,理解和解决这些问题对于确保金融软件的稳健安全至关重要。本篇博客深入探讨了银行应用程序中普遍的加密陷阱,并重点介绍了降低这些风险的最佳实践。 我们将讨论的一些常见陷阱如下:

  • 硬编码加密密钥
  • 使用弱且过时的算法。
  • 为OTP、密码和密钥生成使用不安全的随机数
  • 校验和生成中缺乏SALT

1. 在Javascript代码中硬编码加密密钥:

传输中加密的理念是希望在前所未有的信道泄露事件中保护用户数据。在这些事件中,加密的用户数据会落入攻击者手中。由于数据是加密的,它可能被认为是安全的。但如果你使用的是对称算法,并且在Javascript中硬编码了加密密钥,攻击者可以简单地从JavaScript中获取通用的加密密钥并解密加密的数据。

弱加密方法

作为渗透测试人员,每当你在javascript中看到硬编码的加密密钥时,情况正是如此。即使实施了SSL以保护信道不被中间人(MiTM)攻击者暴露,但由于CA或支持的SSL TLS算法本身的漏洞,信道很少被暴露。

我们观察到许多组织实施了这种加密方式,使其安全状态处于一种伪安全的状态。

如何安全地实施? 在传输中实施加密的理想方式是结合使用RSA和AES。下图展示了如何一起使用这些算法,以针对用户数据获得最佳形式的加密和数据保护。

RSA与AES结合

首先,应用程序使用AES加密数据,然后使用RSA的公钥加密AES密钥。加密后的AES密钥被发送到服务器,服务器使用RSA的私钥对其进行解密。服务器用解密后的AES密钥来解密数据。 我们使用AES进行数据加密,是因为其速度比RSA加密更快,同时使用RSA加密来传输密钥,以挫败潜在的中间人(MiTM)攻击。每个用户生成一个新的AES密钥,确保密钥频繁轮换,并极大地降低了因密钥泄露导致加密数据暴露的可能性。 在这种情况下,即使攻击者能够拦截信道并获取加密数据,他们也无法解密,因为只有服务器持有私钥。因此,这被认为是更安全的数据加密方式。

2. 使用弱和过时的算法:

使用MD5(消息摘要算法5)和SHA-1(安全哈希算法1)哈希算法。这些曾经是验证数据完整性和哈希密码的流行选择。然而,MD5和SHA-1均被发现存在漏洞,容易受到碰撞攻击,即两个不同的输入产生相同的哈希值。像DES这样的加密算法也以存在可被利用来解密数据的漏洞而闻名。由于最早的示例代码是使用这些算法实现的,开发者倾向于复制粘贴这些使用弱算法的代码片段。攻击者可以利用这些算法中的漏洞来获取未经授权的访问、窃取敏感信息或篡改数据。

实现MD5的示例

1
2
3
String filename = "example.txt";
MessageDigest md = MessageDigest.getInstance("MD5");
FileInputStream fis = new FileInputStream(filename);

实现SHA-256的示例

1
2
3
String filename = "example.txt";
MessageDigest md = MessageDigest.getInstance("SHA-256");
FileInputStream fis = new FileInputStream(filename);

从功能的角度来看,对于实现此功能的开发者来说可能没有太大区别,但可能引发安全问题。

3. 为OTP、密码和密钥生成使用不安全的随机数:

为生成一次性密码(OTP)、密码或密钥等任务使用不安全的随机数生成,会损害系统和通信的安全性。不安全的随机数生成可能导致可预测或易于猜测的值,使攻击者更容易拦截或暴力破解认证机制,从而未经授权访问敏感信息或系统。 一个常见的陷阱是使用简单的随机数生成器(RNG),这些生成器不提供足够的随机性或熵。例如,在Java中为加密目的使用java.util.Random类(基于线性同余公式)是不推荐的,因为它可能产生可预测的数字序列。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public static String generateInsecureOTP() {
    Random insecureRandom = new Random(); // 使用Random()生成OTP
    StringBuilder otp = new StringBuilder();
    for (int i = 0; i < 6; i++) {
        otp.append(insecureRandom.nextInt(10));
    }
    return otp.toString();
}

public static void sendSMS(String recipient, String otp) {
    Twilio.init(ACCOUNT_SID, AUTH_TOKEN);
    Message message = Message.creator(
            new PhoneNumber(recipient),
            new PhoneNumber(TWILIO_PHONE_NUMBER),
            "Your OTP is: " + generateInsecureOTP())
        .create();
    System.out.println("OTP sent successfully to " + recipient);
}

一种安全的方法是使用SecureRandom

1
2
3
4
5
6
7
8
public static String generateOTP() {
    SecureRandom random = new SecureRandom();
    StringBuilder otp = new StringBuilder();
    for (int i = 0; i < 6; i++) {
        otp.append(random.nextInt(10));
    }
    return otp.toString();
}

4. 校验和生成中缺乏SALT(或使用弱SALT)

在支付回调请求中实现校验和,是为了确保传输数据的完整性和真实性。当支付被处理,并向商户服务器发送回调请求通知支付状态时,验证接收到的数据在传输过程中未被篡改或损坏至关重要。在确保使用最新算法的同时,还需要检查校验和的生成是否经过加盐处理。

什么是加盐? 加盐是密码学中使用的一种技术,特别是在密码哈希中,通过在哈希前向输入添加随机数据来增强安全性。这种随机数据被称为“盐”。

考虑以下HTTP请求示例,这是一个关于支付交易状态的简单回调。应用程序依赖校验和来验证接收数据的完整性。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
POST /payment_callback HTTP/1.1
Host: example.com
Content-Type: application/json

{
"transaction_id": "123456789",
"amount": 100.50,
"status": "success",
"checksum": "a8dd534163dfd7e1366205499d38f07e"
}

上述请求通过使用“|”连接所有值并创建其MD5哈希来实现校验和。这看起来是安全的,因为我们正在验证接收到的数据,并通过验证MD5哈希来确保其未被篡改。 然而,攻击者会尝试通过尝试各种模式和字符来连接值,从而识别哈希生成方式。一旦攻击者能够找出哈希生成模式,他们就可以操纵数据,为被篡改的数据生成新的校验和,并提交请求,绕过验证过程。

因此,解决方案是在哈希过程中使用不可预测的SALT。

1
2
byte[] salt = fetchSALTfromDB();
String combinedString = transactionId + "|" + amount + "|" + status + "|" + new String(salt);

通过实施此方法,攻击者将无法在不了解SALT的情况下自行生成校验和。

结论

总之,保护银行应用程序的安全不仅仅在于合规;它需要遵循安全的加密实践。硬编码密钥、弱算法、不安全的随机数生成以及校验和中缺乏盐值等常见陷阱,都凸显了细致入微的必要性。开发者不仅必须满足监管标准,还必须以正确和安全的方式实施加密。主动措施,如稳健的加密协议、适当的密钥管理和定期的渗透测试,对于保护敏感的财务数据以及在数字时代维护客户信任至关重要。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计