Java安全中的“大坑”,跨平台真“浮云”

介绍了解决在不同JDK环境下AES加密解密不兼容的问题,采用了一种替代方案确保了HttpDB项目在新浪云服务SAE中的正常运行。

        最近在做一个开源项目HttpDB,它的目标是在互联网中通过JDBC安全的查询数据库,解决云计算报表的数据库访问问题。



 

        数据传输使用AES加密算法,用到了Java提供的安全库javax.crypto.*,经过一通折腾,大功告成。发布  到了新浪云服务SAE中测试,结果我不能淡定了,加密后的数据解密失败。。。

        搞到深夜,无语,问题终于找到了,我本地用的是SUN的JDK,SAE中是OpenJDK,安全算法实现不一致。。。

        后来在Git中找了一个AES的实现替代了JDK的实现,终于搞定了。。。

        成果与大家分享:http://xdoc.sinaapp.com/httpdb.html

 

  • 大小: 42.9 KB
Java开发中,一些看似简单的代码片段可能隐藏着严重的潜在问题,这些问题可能在短期内不会暴露,但一旦发生,往往会造成难以排查的后果。以下是一些常见的简单但容易引发问题的Java代码示例。 ### 3.1 单例模式中的双重检查锁定问题 在实现单例模式时,为了提高性能,开发者常使用双重检查锁定(Double-Checked Locking)模式。然而,如果不正确使用 `volatile` 关键字,可能会导致线程安全问题。 ```java public class LazySingleTon { private static LazySingleTon instance = null; private LazySingleTon(){} public static LazySingleTon getInstance() { if(instance == null){ synchronized (LazySingleTon.class){ if(instance == null){ instance = new LazySingleTon(); } } } return instance; } } ``` 在上述代码中,`instance` 没有使用 `volatile` 修饰,这可能导致指令重排序的问题,从而导致某些线程看到一个未完全构造的实例。为了防止这种问题的发生,应该使用 `volatile` 来修饰 `instance` 变量[^4]。 ### 3.2 使用 `ConcurrentHashMap` 时的复合操作问题 虽然 `ConcurrentHashMap` 是线程安全的集合类,但在执行一些复合操作时,仍然需要额外的同步机制来保证原子性。 ```java public class Cache<K, V> { private final ConcurrentHashMap<K, V> cache = new ConcurrentHashMap<>(); public V get(K key) { return cache.get(key); } public void put(K key, V value) { cache.put(key, value); } // 复合操作需要保证原子性 public V putIfAbsent(K key, V value) { V existing = cache.get(key); if (existing == null) { existing = value; cache.put(key, value); } return existing; } } ``` 在上述代码中,`putIfAbsent` 方法是一个复合操作,包含检查和更新两个步骤。由于 `ConcurrentHashMap` 不保证复合操作的原子性,多个线程同时调用该方法可能会导致数据不一致的问题。因此,应该使用 `ConcurrentHashMap` 提供的原子方法 `putIfAbsent` 来替代自定义实现[^5]。 ### 3.3 ABA 问题 在使用 `CAS`(Compare and Set)操作时,可能会遇到 ABA 问题。这个问题指的是一个值从 A 变成 B,又变回 A,此时 `CAS` 操作会认为该值没有发生变化,但实际上中间已经发生了修改。 ```java AtomicReference<Integer> atomicReference = new AtomicReference<>(1); new Thread(() -> { atomicReference.compareAndSet(1, 2); atomicReference.compareAndSet(2, 1); }).start(); new Thread(() -> { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } boolean success = atomicReference.compareAndSet(1, 3); System.out.println("CAS success: " + success); }).start(); ``` 在上述代码中,第一个线程将 `atomicReference` 的值从 1 改为 2,然后再改回 1。第二个线程在执行 `CAS` 操作时会成功,因为它无法感知到中间的变化。为了解决这个问题,可以使用 `AtomicStampedReference` 来为每次修改添加版本号,从而区分值是否正发生变化[^3]。 ### 3.4 类型转换问题 在进行类型转换时,如果不进行类型检查,可能会导致 `ClassCastException`。 ```java Object obj = "Hello"; Integer i = (Integer) obj; // 抛出 ClassCastException ``` 在上述代码中,`obj` 是一个 `String` 类型的对象,尝试将其强制转换为 `Integer` 类型会导致运行时异常。为了避免此类问题,可以在转换前使用 `instanceof` 进行类型检查。 ```java if (obj instanceof Integer) { Integer i = (Integer) obj; } ``` ### 3.5 异常处理不当 在捕获异常时,如果直接捕获 `Exception` 或 `Throwable`,而没有进行适当的处理,可能会掩盖潜在的问题。 ```java try { // 可能抛出异常的代码 } catch (Exception e) { // 忽略异常 } ``` 在上述代码中,所有异常都被捕获并忽略,导致问题无法及时发现。正确的做法是捕获特定的异常,并记录日志或采取适当的恢复措施。 ```java try { // 可能抛出异常的代码 } catch (IOException e) { e.printStackTrace(); } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值