1. 程式人生 > >java hash碰撞分析模擬

java hash碰撞分析模擬

for java:      

依靠相應語言的hashtable/hashmap實現過程(request多為此結構),當不同的key存入時如果hash值相等則以連結串列方式連線在前面。此漏洞利用碰撞相同的hash值得到一個長連結串列, 重新get時,map的計算過程會將時間複雜度巨增,原來一個簡單的過程將變成一個很費cpu的過程。 常見的伺服器會將使用者post的資料儲存在hashmap中. 而向hashmap中插入n對元素的時間複雜度大約是O(n), 但如果精心構造key使得每個key的hash值相同(也就是產生了碰撞),則時間複雜度會惡化到O(n^2),導致消耗大量的CPU時間.

模擬實現

public class Hash {

public static void main(String[] args) {

HashMap<App, String>hash=new HashMap<App, String>();
Long start=System.currentTimeMillis();
for (Integer i = 0; i < 65536 ; i++) {
App app=new App();
app.setId(100);
hash.put(app, i.toString());
}
App app2=new App();
app2.setId(100);

hash.get(app2);
Long end=System.currentTimeMillis();
System.out.println("第一種方式"+(end-start)/1000);//33

HashMap<App, String>hash2=new HashMap<App, String>();
Long start2=System.currentTimeMillis();
for (Integer i = 0; i < 65536 ; i++) {
App app=new App();
app.setId(i);
hash2.put(app, i.toString());
}
App app3=new App();
app3.setId(100);
hash2.get(app3);
Long end2=System.currentTimeMillis();
System.out.println("第2種方式"+(end2-start2)/1000);
}
}


結果:第一種方式138

第二種:0

---------------------------------------

public class App {
  
private Integer id;
    
    public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Override
    public boolean equals(Object obj) {
    // TODO Auto-generated method stub
    return super.equals(obj);
    }
    @Override
    public int hashCode() {
    // TODO Auto-generated method stub
    return id;
    }
}

------------------------------------------

檢視原始碼

  final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;//node 儲存值的資料結構
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;   // 初始化長度
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);//根據hash值計算值卡槽(值所在hashmap的位置)
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))  //hash值相同key地址相同 或key的值相等
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {        //p為hash值相等的連結串列最後一個元素
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }


hash碰撞出現的情景?
(1)一般會出現在大的資料情況之下
(2)hashcode的生成方法唯一性較弱(比如上面的人為的生產hashcode)