薄弱加密实践如何危及银行软件安全

本文深入分析银行应用程序中常见的加密安全漏洞,包括硬编码密钥、使用弱算法、不安全随机数生成和缺乏盐值等关键问题,并提供相应的安全解决方案和最佳实践建议。

在当今数字时代,金融机构严重依赖加密技术来保护银行应用中的敏感数据。然而,尽管密码学扮演着关键角色,许多实现却存在根本性缺陷,造成了虚假的安全感。对密码学原理的误解,加上快速符合安全标准的努力,常常导致使用弱或过时的算法、不当的密钥管理和有缺陷的加密协议。这些常见错误使银行客户容易受到攻击,导致数据泄露和财务损失等严重后果。理解和解决这些问题对开发人员确保金融软件的稳健安全至关重要。

我们将讨论的一些常见陷阱包括:

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

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

传输中加密的理念是希望在使用通道遭到破坏的意外事件中保护用户数据。在这些事件中,加密的用户数据会落入坏人手中。由于数据已加密,可能被认为是安全的。但如果你在使用对称算法并在Javascript中硬编码加密密钥,对手可以简单地从JavaScript获取通用加密密钥并解密加密数据。

作为渗透测试人员,每当你在javascript中看到硬编码的加密密钥时,这正是发生的情况。即使实施了SSL并保护通道免受中间人攻击者的暴露,但由于CA或支持的SSL TLS算法本身的漏洞,很少会暴露。

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

如何安全地实施?

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

最初,应用程序使用AES加密数据,然后使用RSA公钥加密AES密钥。加密的AES密钥发送到服务器,服务器使用RSA私钥解密。使用解密的AES密钥,服务器解密数据。

我们使用AES进行数据加密,因为其速度优于RSA加密,同时使用RSA加密传输密钥以阻止潜在的中间人攻击。每个用户生成新的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、密码和密钥生成使用不安全随机数生成

为生成一次性密码、密码或密钥等任务使用不安全随机数生成可能损害系统和通信的安全。不安全随机数生成可能导致可预测或容易猜测的值,使攻击者更容易拦截或暴力破解认证机制,并获得对敏感信息或系统的未经授权访问。

一个常见陷阱是使用不提供足够随机性或熵的简单随机数生成器。例如,在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. 校验和生成中缺乏盐值(或弱盐值)

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

什么是加盐?

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

考虑以下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哈希确保其未被篡改。

然而,对手尝试通过尝试各种模式和字符连接值来识别哈希。一旦攻击者能够找出哈希生成模式,他们就可以操纵数据,为被篡改的数据生成新的校验和,并提交请求,绕过验证过程。

解决方案是在哈希过程中使用不可预测的盐值。

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

通过实施这一点,攻击者将没有任何机会在不知道盐值的情况下自行生成校验和。

结论

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

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