cookie防篡改
概述:
除了session外,一般不會在客戶端的cookies里保存過于重要的憑據(jù),但電商應(yīng)用有時候不可避免地存儲了一些敏感數(shù)據(jù)到客戶端,當(dāng)然不希望被篡改。
目的:
讓服務(wù)器端能識別cookie值被篡改了。
手法:
set-cookie時加上防篡改驗證碼。
如:
user_name=alex|bj95ef23cc6daecc475de
防篡改驗證碼的生成規(guī)則可以很簡單:md5(cookieValue+key)或sha1(cookieValue+key),key可以是服務(wù)器端掌握的一個固定字符串,也可以很復(fù)雜(如后面的LTPA示例)。
核對規(guī)則是:
服務(wù)器端得到客戶端送上來的cookie后,重新計算一下驗證碼,如一致,則未篡改。
示例2:IBM LTPA 的cookie簽名
Lightweight Third-Party Authentication (LTPA)是IBM Websphere和Domino產(chǎn)品中使用的單點登錄技術(shù)。
當(dāng)服務(wù)器配置好LTPA認(rèn)證方式,用戶通過瀏覽器成功登錄后,服務(wù)器會自動發(fā)送一個session cookie給瀏覽器;此Cookie中包含一個LTPA Token。
一個有效的LTPA Cookie能夠在同一個認(rèn)證域中被所有服務(wù)器自動認(rèn)證。此Cookie中包含認(rèn)證信息和時間戳。這些信息通過共享的3DES Key進行了bis 加密。使用公共密鑰/私有密鑰進行簽名。
1)大致介紹:
LTPA Cookie原始值通過3DES密鑰,使用DESede/ECB/PKCS5P進行加密。
此3DES密鑰也是采用DESede/ECB/PKCS5P進行加密,加密后再使用事先提供的密鑰密碼 進行SHA-1 Hash,生成24個字節(jié)的密鑰,再進行Base64編碼。
如Dmonio里,LTPA Cookie值為以下公式組成:
SHA-1=LTPA版本號+創(chuàng)建時間+過期時間+用戶名+Domino LTPA 密鑰
LTPA Cookie= Base64(LTPA版本號+創(chuàng)建時間+過期時間+用戶名+SHA-1)
如要解析LTPA Token,先得使用密鑰密碼 ,生成3DES密鑰;再使用3DES密鑰 解密 Token Cookie。也可以使用公共/私有密鑰來簽名或驗證LTPA Cookie。
2)WebSphere LTPA 生成原理
首先,這個 cookie 由以下部分組成,以%進行分隔:
用戶信息 ,格式為u:user\:<RealmName>/<UserDN>,如:u:user\:VGOLiveRealm/CN=squallzhong,O=VGOLive Technology
過期時間
簽名信息, 如:
u:user\:VGOLiveRealm/CN=squallzhong,O=VGOLive Technology%1301558320666%Cy2CAeru5kEElGj0hrvYsKW2ZVsvvcu6Un573aeX55OO4G3EMYWc0e/ZbqDp1z7MS+
dLzniuUH4sYWCMpnKdm7ZGabwmV+WcraBl+y+yzwcl722gHVMOnDZAW7U3jEay9
Tk2yG4yXkMWU+617xndpVxke2jtS5wIyVVM3q7UDPw=
3)WebSphere LTPA Cookie 的解析
以下代碼為解析從 WebSphere 或 Domino 發(fā)送過來的 LTPAToken Cookie。以Java為例:
01…
02 // LTPA 3DES 密鑰
03 String ltpa3DESKey = "7dH4i81YepbVe+gF9XVUzE4C1Ca5g6A4Q69OFobJV9g=";
04 // LTPA 密鑰密碼
05 String ltpaPassword = "Passw0rd";
06 try {
07 // ***步,獲得加密key
08 byte[] secretKey = getSecretKey(ltpa3DESKey, ltpaPassword);
09 // 第二步,使用加密key解密ltpa Cookie
10 String ltpaPlaintext = new String(decryptLtpaToken(tokenCipher,
11 secretKey));
12 displayTokenData(ltpaPlaintext);
13 } catch (Exception e) {
14 System.out.println("Caught inner: " + e);
15 }
16…
17 //獲得安全Key
18 private static byte[] getSecretKey(String ltpa3DESKey, String password)
19 throws Exception {
20 // 使用SHA獲得key密碼的hash值
21 MessageDigest md = MessageDigest.getInstance("SHA");
22 md.update(password.getBytes());
23 byte[] hash3DES = new byte[24];
24 System.arraycopy(md.digest(), 0, hash3DES, 0, 20);
25 // 使用0替換后4個字節(jié)
26 Arrays.fill(hash3DES, 20, 24, (byte) 0);
27 // BASE64解碼 ltpa3DESKey
28 byte[] decode3DES = Base64.decodeBase64(ltpa3DESKey.getBytes());
29 // 使用key密碼hash值解密已Base64解碼的ltpa3DESKey
30 return decrypt(decode3DES, hash3DES);
31 }
32 //解密LtpaToken
33 public static byte[] decryptLtpaToken(String encryptedLtpaToken, byte[] key)
34 throws Exception {
35 // Base64解碼LTPAToken
36 final byte[] ltpaByteArray = Base64.decodeBase64(encryptedLtpaToken
37 .getBytes());
38 // 使用key解密已Base64解碼的LTPAToken
39 return decrypt(ltpaByteArray, key);
40 }
41 // DESede/ECB/PKC5Padding解方法
42 public static byte[] decrypt(byte[] ciphertext, byte[] key)
43 throws Exception {
44 final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
45 final KeySpec keySpec = new DESedeKeySpec(key);
46 final Key secretKey = SecretKeyFactory.getInstance("TripleDES")
47 .generateSecret(keySpec);
48 cipher.init(Cipher.DECRYPT_MODE, secretKey);
49 return cipher.doFinal(ciphertext);
50 }
51…
解析出來的LTPAToken信息以%分隔。
參考資源:
1)hannover,LTPA Cookie原理