`
C_J
  • 浏览: 127858 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

可变hashcode的隐患和序列化安全

阅读更多

可变hashcode的隐患

 

    为识别对象,JDK为每个Object类都定义了一个hashcode,Object的类的hashcode是根据对象的内存地址做hash算法得出来的,String类则自己重写了hashcode()方法,是根据字符串的每个字符做算法累加起来的,Integer在直接返回value的值。

    而很多时候,对于应用系统的一些类(Java Bean),是要根据属性来计算hashcode而非内存地址,就像String类。所以会去覆盖Object的equals方法。其实重写就重写了,但是出于技术上的要求,JDK的一些数据结构Collection作为一个数据的容器,它需要唯一定位某个对象,而判定对象是否相等的标准是:1,hashcode是否相等;2,equals函数是否返回true。所以如果这些Java Bean用到这些Collection的话重写equals就必须同时重写hashcode了。

    但这不是重点,重点是另外一个问题:可变的hashcode带来的BUG。

 

大师Ted给出了例子,如下:

import java.util.*;

public class Person
    implements Iterable<Person>
{
    public Person(String fn, String ln, int a, Person... kids)
    {
        this.firstName = fn; this.lastName = ln; this.age = a;
        for (Person kid : kids)
            children.add(kid);
    }
    
    // ...
    
    public void setFirstName(String value) { this.firstName = value; }
    public void setLastName(String value) { this.lastName = value; }
    public void setAge(int value) { this.age = value; }
    
    public int hashCode() {
        return firstName.hashCode() & lastName.hashCode() & age;
    }

    // ...

    private String firstName;
    private String lastName;
    private int age;
    private List<Person> children = new ArrayList<Person>();
}


// MissingHash.java
import java.util.*;

public class MissingHash
{
    public static void main(String[] args)
    {
        Person p1 = new Person("Ted", "Neward", 39);
        Person p2 = new Person("Charlotte", "Neward", 38);
        System.out.println(p1.hashCode());
        
        Map<Person, Person> map = new HashMap<Person, Person>();
        map.put(p1, p2);
        
        p1.setLastName("Finkelstein");
        System.out.println(p1.hashCode());
        
        System.out.println(map.get(p1));
    }
}

 

    可以看到这个Person重写了hashcode,是属性的hashcode做与运算得出的结果。但是注意到,当p1对象作为key放入HashMap后,随后改变了lastName的属性,导致p1对象的hashcode发生了改变,从而System.out.println(map.get(p1));直接输出null。

    所以可以看到,在重写hashcode的时候要特别注意可变的hashcode的影响,为了消除这种隐患,最好给属性加上final的限制。

 

 

序列化安全问题

    java中序列化对象可以用户磁盘存储和网络传输对象等,但如果不经过任何处理则这些流都是明文的,具有安全隐患,我们通过模糊化处理或使用SealedObject加密等方法来保证安全,如下:

 

1,模糊化处理,如下:

    JAVA对于序列化、反序列化的类是利用ObjectOutputStream、ObjectIntputStream实现,如果需要序列化的类没有writeObject和readObject的方法话,则会调用默认的序列化方式,所以只要重写这两个方法就可以实现自定义的方式来增加安全性等特殊处理(JDK应该是考虑到了安全等问题才给与扩展),如下:

package com.tedneward;

public class Person
    implements java.io.Serializable
{
    public Person(String fn, String ln, int a)
    {
        this.firstName = fn; this.lastName = ln; this.age = a;
    }
    
    public String getFirstName() { return firstName; }
    public String getLastName() { return lastName; }
    public int getAge() { return age; }
    public Person getSpouse() { return spouse; }
    
    public void setFirstName(String value) { firstName = value; }
    public void setLastName(String value) { lastName = value; }
    public void setAge(int value) { age = value; }
    public void setSpouse(Person value) { spouse = value; }
    
    private void writeObject(java.io.ObjectOutputStream stream)
        throws java.io.IOException
    {
        // "Encrypt"/obscure the sensitive data
        age = age << 2;
        stream.defaultWriteObject();
    }
    
    private void readObject(java.io.ObjectInputStream stream)
        throws java.io.IOException, ClassNotFoundException
    {
        stream.defaultReadObject();

        // "Decrypt"/de-obscure the sensitive data
        age = age >> 2;
    }
    
    
    private String firstName;
    private String lastName;
    private int age;
    private Person spouse;
}

 

 

 

 

2,使用SealedObject对对象进行加密,然后序列化,如下:

 

 

import java.io.Serializable;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SealedObject;
import javax.crypto.SecretKey;

public class MainClass {
  public static void main(String args[]) throws Exception {
    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    SecretKey secretKey;
    Cipher encrypter, decrypter;

    secretKey = KeyGenerator.getInstance("DES").generateKey();// des加密

    encrypter = Cipher.getInstance("DES");
    encrypter.init(Cipher.ENCRYPT_MODE, secretKey);

    decrypter = Cipher.getInstance("DES");
    decrypter.init(Cipher.DECRYPT_MODE, secretKey);

    MyClass cust, unsealed;
    SealedObject sealed;

    cust = new MyClass();
    cust.name = "Paul";
    cust.password = "password";

    // Seal it, storing it in a SealedObject
    sealed = (new SealedObject(cust, encrypter));
    
    FileOutputStream fos = new FileOutputStream(args[0]);
    ObjectOutputStream oos = new ObjectOutputStream(fos);
    oos.writeObject(sealed);
    oos.close();

    // Try unsealing it
    String algorithmName = sealed.getAlgorithm();
    System.out.println(algorithmName);
    unsealed = (MyClass) sealed.getObject(decrypter);

    System.out.println("NAME: " + unsealed.name);
    System.out.println("PASSWORD: " + unsealed.password);

  }
}

class MyClass implements Serializable {
  public String name;

  public String password;
}

 

 

分享到:
评论

相关推荐

    java 序列化和重写 hashCode 的原因

    在Java编程语言中,序列化(Serialization)和重写`hashCode`及`equals`方法是两个重要的概念,它们各自有着特定的用途,并且在某些情况下相互关联。下面将详细阐述这两个概念及其应用。 首先,Java序列化是将一个...

    JAVA_高级特性(hashCode,clone,比较器,Class反射,序列化)

    ### Java 高级特性详解 #### 一、`hashCode` ...正确地重写 `equals` 和 `hashCode` 方法、使用 `Comparator` 进行排序、利用反射机制和序列化技术,以及实现 `clone` 方法都是开发高质量 Java 应用程序的重要技能。

    hashcode和equals方法

    equals()和hashcode()这两个方法都是从object类中继承过来的。当String 、Math、还有Integer、Double。。。。等这些封装类在使用equals()方法时,已经覆盖了object类的equals()方法.

    Java反序列化入门之URLDNS链1

    Java反序列化漏洞是一种安全问题,主要出现在Java应用程序中,当程序不安全地处理来自不可信源的反序列化数据时,攻击者可以构造恶意序列化对象,导致非预期的对象创建或代码执行。本文将深入探讨Java反序列化的基本...

    URLDNS反序列化链学习.doc

    总的来说,URLDNS反序列化链是Java安全领域的一个重要知识点,了解其工作原理和防范措施对于开发安全的应用至关重要。通过学习和理解这种攻击手段,开发者可以更好地保护他们的系统免受潜在的威胁。

    HashCode的用法详解

    hashCode 是一种用于查找和排序的机制,在数据结构中 plays a crucial role。下面我们将对 hashCode 的用法进行详细的解释。 hashCode 的作用 hashCode 的主要作用是用于查找和排序。在查找和排序的过程中,我们...

    关于hashCode()和equals()的本质区别和联系

    hashCode() 和 equals() 的本质区别和联系 Java 中的每个对象都有 hashCode() 和 equals() 方法,这两个方法的正确实现对于 Java 开发人员来说是非常重要的。本文将详细介绍 hashCode() 和 equals() 的本质区别和...

    深入 HashCode 方法~

    ### 深入理解 HashCode 方法 #### 一、HashCode 的基本概念与...通过合理地设计和实现 `HashCode`,可以大大提高程序的运行效率和性能。对于自定义类来说,正确地重写 `hashCode()` 和 `equals()` 方法是非常必要的。

    重写equals和hashcode方法_equals_重写equals和hashcode方法_

    在Java编程语言中,`equals()` 和 `hashCode()` 方法是Object类中的两个核心方法,所有类都默认继承自Object类。这两个方法在处理对象比较和集合操作时起着至关重要的作用。当我们创建自定义类并需要对对象进行精确...

    immutables,用于创建不可变对象和生成器的注释处理器。感觉像是番石榴的不可变集合,但对于常规值对象。包括json、jackson、gson、jax-rs、mongodb集成.zip

    对于Jackson的集成,只需要添加对应的依赖,Immutables会自动处理不可变对象的序列化和反序列化。同样,对于Gson,也有对应的适配器帮助处理。至于MongoDB,Immutables提供了BSON编码/解码器,使得不可变对象可以...

    Java中equals,hashcode和==的区别

    "Java中equals、hashcode和==的区别" Java 中 equals、hashcode 和==的区别是 Java 编程语言中一个经常遇到的问题。这三个概念都是用来比较对象的,但是它们之间存在着本质的区别。 首先,==号是Java中的一个...

    java中hashcode()和equals()方法详解

    在Java编程语言中,`hashCode()`和`equals()`方法是非常重要的概念,它们不仅对于深入理解Java内存管理至关重要,也是实现自定义类的关键部分之一。本文将详细介绍这两个方法的工作原理、使用场景以及它们之间的关系...

    hashcode()和equals()

    在Java编程语言中,`hashCode()` 和 `equals()` 方法是两个非常重要的概念,尤其是在处理对象比较和哈希表(如 `HashMap` 或 `HashSet`)时。这两个方法来源于 `Object` 类,是所有Java类的基类,因此,每个自定义类...

    hashcode和equals的分析

    2. **可变性**:如果两个对象的`hashCode`值相同,并不一定意味着这两个对象相等。 ### 3. 实例分析 假设我们有一个名为`Person`的类,其中包含`name`和`age`两个属性。为了使`Person`对象能够正确地工作在`...

    java中hashcode()和equals()和==的详解

    有许多人学了很长时间的Java,但一直不明白hashCode方法的作用以及equals()和==的区别,我来解释一下吧。首先,想要明白hashCode的作用,你必须要先知道Java中的集合。总的来说,Java中的集合(Collection)有两类,...

    Java理论与实践:hashCode()和equals()方法

    本文还介绍了定义对象的相等性、实施equals()和hashCode()的需求、编写自己的equals()和hashCode()方法。通过统一定义equals()和hashCode(),可以提升类作为基于散列的集合中的关键字的使用性。

    利用反射绕过编译器和hashcode高级应用

    在Java编程语言中,反射(Reflection)是一种强大的...但需要注意的是,滥用反射可能导致安全问题和性能下降,因此在实际使用中需谨慎权衡。同样,正确实现和使用hashcode也是优化程序性能和保证数据结构正确性的关键。

    java中hashcode()和equals()的详解

    Java的`Objects.equals()`和`Objects.hash()`方法是帮助我们更安全地处理`equals()`和`hashCode()`的实用工具。`Objects.equals(a, b)`可以避免空指针异常,当a或b为null时,它会正确处理。而`Objects.hash()`可以...

    equals与hashCode方法讲解

    equals 方法和 hashCode 方法是 Java 语言中两个重要的方法,它们都是在 Object 类中定义的。equals 方法用于比较两个对象是否相等,而 hashCode 方法用于返回对象的哈希码。 在 Java 的 Object 类中,equals 方法...

Global site tag (gtag.js) - Google Analytics