《實戰開發》一個基於時間戳的控制失效二維碼的漏洞

項目需求:第三方生成一個帶13位時間戳參數的二維碼,掃碼後進入我的網站,我根據二維碼中時間戳(二維碼生成時間),和當前時間戳進行比較,如果詳相減後大於某個值(10分鐘、1天這種變量),則系統會提示二維碼失效,否則,將會正常訪問。

初步設計方案

獲取二維碼中的13位時間戳,用當前時間戳減去二維碼中生成的時間戳(單位是毫秒),如果大於失效時間,則認位二維碼失效,那麼會返回一個錯誤頁面。代碼如下:

public class QrTest {

	public static void main(String[] args) {
		// 獲得二維碼的生成時間戳
		String	qct =1566447946620;

		String failTime = "1" ; // 這裏默認失效爲1秒
		// 二維碼失效控制(單位:秒)
		long currentTime = System.currentTimeMillis();
		Long crTime = Long.parseLong(qct);
		
		// 如果失效,則返回錯誤信息
		if( (currentTime - crTime ) / 1000 >  Long.parseLong(failTime)) {
			System.out.println("失效");
		}else {
			System.out.println("有效");
		}
		System.out.println("當前時間戳:" + currentTime);
		System.out.println("二維碼生成時間戳:" + crTime);
		System.out.println("失效時間:" + failTime);
		System.out.println("當前時間減去創建時間:" + (currentTime - crTime) );
		System.out.println("當前時間減去創建時間(單位秒):" + (currentTime - crTime ) / 1000);
		System.out.println("是否失效:" + ((currentTime - crTime ) / 1000 >  Long.parseLong(failTime)) );
	}
}

這樣看起來是沒有問題的,程序也可以正常處理。但是在做測試的時候,發現如果用一個未來的時間戳,或者用年月日時分秒這種格式的字符串,就可以失效繞過。代碼如下:

		// 獲得二維碼的生成時間戳
		//String	qct = "1566447946620";
		String	qct = "1766556549896";//未來時間
	//	String	qct = "2019082113211";//2.2019082113211
	//	String	qct = "20190821132113";//3.20190821132113
		
		// 查詢該銀行的失效時間
		String failTime = "1" ; // 默認失效爲1秒
		// 二維碼失效控制(單位:秒)
		long currentTime = System.currentTimeMillis();
		Long crTime = Long.parseLong(qct);
		
		// 如果失效,則返回錯誤信息
		if( (currentTime - crTime ) / 1000 >  Long.parseLong(failTime)) {
			System.out.println("失效");
		}else {
			System.out.println("有效");
		}
		System.out.println("當前時間戳:" + currentTime);
		System.out.println("二維碼生成時間戳:" + crTime);
		System.out.println("失效時間:" + failTime);
		System.out.println("當前時間減去創建時間:" + (currentTime - crTime) );
		System.out.println("當前時間減去創建時間(單位秒):" + (currentTime - crTime ) / 1000);

運行結果:
在這裏插入圖片描述

發現,上面三種情況均可以實現繞過失效的控制,隨後發現,問題在於"當前時間減去創建時間:" (currentTime - crTime),上面三種情況下,相減結果必然是負數,那麼根據這個思路進行優化。代碼如下:


	//非法時間戳: 都會、造成currentTime - crTime爲負數,這樣和當前時間戳比較後均可以繞過,實現繞過
	//1.未來時間的時間戳
	//2.時間格式的日期:2019082113211
	//3..時間格式的日期:20190821132113
	public static void main(String[] args) {
		// 獲得二維碼的生成時間戳
		//String	qct = "1566447946620";
		String	qct = "1766556549896";//未來時間
	//	String	qct = "2019082113211";//2.2019082113211
	//	String	qct = "20190821132113";//3.20190821132113
		
		// 查詢該銀行的失效時間
		String failTime = "1" ; // 默認失效爲1秒
		// 二維碼失效控制(單位:秒)
		long currentTime = System.currentTimeMillis();
		Long crTime = Long.parseLong(qct);
		
		// 如果失效,則返回錯誤信息
		if( (currentTime - crTime ) / 1000 >  Long.parseLong(failTime)) {
			System.out.println("失效");
		}else {
			System.out.println("有效");
		}
		System.out.println("當前時間戳:" + currentTime);
		System.out.println("二維碼生成時間戳:" + crTime);
		System.out.println("失效時間:" + failTime);
		System.out.println("當前時間減去創建時間:" + (currentTime - crTime) );
		System.out.println("當前時間減去創建時間(單位秒):" + (currentTime - crTime ) / 1000);
		System.out.println("是否失效:" + ((currentTime - crTime ) / 1000 >  Long.parseLong(failTime)) );
		
		//優化方案:"當前時間減去創建時間:" + (currentTime - crTime)  爲負數,則存在繞過嫌疑,將直接判定爲失效
		// 如果失效,則返回錯誤信息
		// 如果失效,則返回錯誤信息
		if( (currentTime - crTime ) / 1000 < 0) {
			System.out.println("優化後失效");
		} else 	if( (currentTime - crTime ) / 1000 >  Long.parseLong(failTime) ) {
			System.out.println("失效");
		} else {
			System.out.println("有效");
		}
		
	}

在這裏插入圖片描述

歡迎關注本人個人公衆號,交流更多技術信息

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章