• java基础每日学习20131029--序列化


    原则4.1 敏感对象发送出信任区域前进行签名并加密

    说明:敏感数据传输过程中要防止窃取和非法篡改。使用安全的加密算法给数据加密可以防止数据被窃取。而对数据加上数字签名则可以防止数据被非法篡改。在以下场景中,需要加密和数字签名的机制保证数据安全:
    1)序列化或传输敏感数据;2)无SSL传输通道或者代价太高;3)敏感数据需要长久保存;应该要避免使用私有加密算法,以免引入更多的漏洞。应用程序在readObject()writeObject()方法中使用私有加密算法是典型的反例。本规则的错误示例代码和推荐做法都是基于下面的代码来说明:

    class SerializableMap<K, V> implements Serializable 
    { 
        final static long serialVersionUID = -2648720192864531932L; 
        
        private Map<K, V> map; 
        
        public SerializableMap() 
        { 
            map = new HashMap<K, V>(); 
        } 
        
        public Object getData(K key) 
        { 
            return map.get(key); 
        } 
        
        public void setData(K key, V data) 
        { 
            map.put(key, data); 
        } 
    } 
    
    public class MapSerializer 
    { 
        public static SerializableMap<String, Integer> buildMap() 
        { 
            SerializableMap<String, Integer> map = new SerializableMap<String, Integer>(); 
            map.setData("John Doe", new Integer(123456789)); 
            map.setData("Richard Roe", new Integer(246813579)); 
            return map; 
        } 
        
        public static void InspectMap(SerializableMap<String, Integer> map) 
        { 
            System.out.println("John Doe's number is " + map.getData("John Doe")); 
            System.out.println("Richard Roe's number is " 
                    + map.getData("Richard Roe")); 
        } 
        
        public static void main(String[] args) 
        { 
            // ... 
        } 
    } 
    错误示例1:未做任何安全防护 
    public static void main(String[] args) throws IOException, 
        ClassNotFoundException 
    { 
        // Build map 
        SerializableMap<String, Integer> map = buildMap(); 
        // Serialize map 
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("data")); 
        out.writeObject(map); 
        out.close(); 
        // Deserialize map 
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("data")); 
        map = (SerializableMap<String, Integer>) in.readObject(); 
        in.close(); 
        // Inspect map 
        InspectMap(map);       
    } 
    错误示例2:只加密 
    public static void main(String[] args) throws IOException, 
            GeneralSecurityException, ClassNotFoundException 
    { 
        // Build map 
        SerializableMap<String, Integer> map = buildMap(); 
        // Generate sealing key & seal map 
        KeyGenerator generator; 
        generator = KeyGenerator.getInstance("AES"); 
        generator.init(new SecureRandom()); 
        Key key = generator.generateKey(); 
        Cipher cipher = Cipher.getInstance("AES"); 
        cipher.init(Cipher.ENCRYPT_MODE, key); 
        SealedObject sealedMap = new SealedObject(map, cipher); 
        // Serialize map 
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("data")); 
        out.writeObject(sealedMap); 
        out.close(); 
        // Deserialize map 
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("data")); 
        sealedMap = (SealedObject) in.readObject(); 
        in.close(); 
        // Unseal map 
        cipher = Cipher.getInstance("AES"); 
        cipher.init(Cipher.DECRYPT_MODE, key); 
        map = (SerializableMap<String, Integer>) sealedMap.getObject(cipher); 
        // Inspect map 
        InspectMap(map); 
    } 
    错误示例3:先加密后签名 
    public static void main(String[] args) throws IOException, GeneralSecurityException, ClassNotFoundException 
    { 
        // Build map 
        SerializableMap<String, Integer> map = buildMap(); 
        // Generate sealing key & seal map 
        KeyGenerator generator; 
        generator = KeyGenerator.getInstance("AES"); 
        generator.init(new SecureRandom()); 
        Key key = generator.generateKey(); 
        Cipher cipher = Cipher.getInstance("AES"); 
        cipher.init(Cipher.ENCRYPT_MODE, key); 
        SealedObject sealedMap = new SealedObject(map, cipher); 
        // Generate signing public/private key pair & sign map 
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA"); 
        KeyPair kp = kpg.generateKeyPair(); 
        Signature sig = Signature.getInstance("SHA1withDSA"); 
        SignedObject signedMap = new SignedObject(sealedMap, kp.getPrivate(), sig); 
            // Serialize map 
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("data")); 
        out.writeObject(signedMap); 
        out.close(); 
        // Deserialize map 
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("data")); 
        signedMap = (SignedObject) in.readObject(); 
        in.close(); 
        // Verify signature and retrieve map 
        if (!signedMap.verify(kp.getPublic(), sig)) 
        { 
            throw new GeneralSecurityException("Map failed verification"); 
        } 
        sealedMap = (SealedObject) signedMap.getObject(); 
        // Unseal map 
        cipher = Cipher.getInstance("AES"); 
        cipher.init(Cipher.DECRYPT_MODE, key); 
        map = (SerializableMap<String, Integer>) sealedMap.getObject(cipher); 
        // Inspect map 
        InspectMap(map); 
    } 
    这段代码先对数据进行加密,然后再对加密后的数据进行签名。这样做无法保证签名来自数据的原始来源。 
    任何恶意的第三方可以截获原始加密签名后的数据,剔除原始的签名,并对密封的数据加上自己的签名。 
    这样的话,即使恶意第三方无法获取原始的数据内容,正常的接收者也无法得到原始的数据。 
    推荐做法:先签名后加密 
    public static void main(String[] args) throws IOException, GeneralSecurityException, ClassNotFoundException 
    { 
        // Build map 
        SerializableMap<String, Integer> map = buildMap(); 
        // Generate signing public/private key pair & sign map 
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA"); 
        KeyPair kp = kpg.generateKeyPair(); 
        Signature sig = Signature.getInstance("SHA1withDSA"); 
        SignedObject signedMap = new SignedObject(map, kp.getPrivate(), sig); 
        // Generate sealing key & seal map 
        KeyGenerator generator; 
        generator = KeyGenerator.getInstance("AES"); 
        generator.init(new SecureRandom()); 
        Key key = generator.generateKey(); 
        Cipher cipher = Cipher.getInstance("AES"); 
        cipher.init(Cipher.ENCRYPT_MODE, key); 
        SealedObject sealedMap = new SealedObject(signedMap, cipher); 
        // Serialize map 
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream( 
                    "data")); 
        out.writeObject(sealedMap); 
        out.close(); 
        // Deserialize map 
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("data")); 
        sealedMap = (SealedObject) in.readObject(); 
        in.close(); 
        // Unseal map cipher = Cipher.getInstance("AES"); 
        cipher.init(Cipher.DECRYPT_MODE, key); 
        signedMap = (SignedObject) sealedMap.getObject(cipher); 
        // Verify signature and retrieve map 
        if (!signedMap.verify(kp.getPublic(), sig)) 
        { 
            throw new GeneralSecurityException("Map failed verification"); 
        } 
        map = (SerializableMap<String, Integer>) signedMap.getObject(); 
        // Inspect map 
        InspectMap(map); 
    } 
    先签名后加密,既能保证数据的真实可靠性,又能防止“中间人攻击”(man-in-middle attacks)。
    

      

  • 相关阅读:
    groovy集合
    groovy函数、字符串、循环
    groovy运行程序和类型推断
    常见IT英语短语一
    常见IT英语单词
    认识Groovy
    maven入门
    springboot之内嵌tomcat修改端口号
    springboot手动配置数据源:
    img与父元素的间隙解决
  • 原文地址:https://www.cnblogs.com/tjw-nau/p/3393783.html
Copyright © 2020-2023  润新知