電商課題:cookie防篡改


@鄭昀匯總 

關鍵詞: cookie poisoning
概述:
除了 session 外,一般不會在客戶端的 cookies 里保存過於重要的憑據,但電商應用有時候不可避免地存儲了一些敏感數據到客戶端,當然不希望被篡改。

目的:
讓服務器端能識別cookie值被篡改了。
 
手法:
set-cookie時加上防篡改驗證碼。
如:
user_name=alex|bj95ef23cc6daecc475de
 
防篡改驗證碼的生成規則可以很簡單:md5(cookieValue+key)或sha1(cookieValue+key),key可以是服務器端掌握的一個固定字符串,也可以很復雜(如后面的LTPA示例)。
 
服務器端得到客戶端送上來的cookie后,重新計算一下驗證碼,如一致,則未篡改。
 
示例2:IBM LTPA 的 cookie 簽名
Lightweight Third-Party Authentication (LTPA)是IBM Websphere和Domino產品中使用的單點登錄技術。
當服務器配置好LTPA認證方式,用戶通過瀏覽器成功登錄后,服務器會自動發送一個 session cookie 給瀏覽器;此 Cookie 中包含一個 LTPA Token。
一個有效的 LTPA Cookie 能夠在同一個認證域中被所有服務器自動認證。此 Cookie 中包含認證信息和時間戳。這些信息通過共享的 3DES Key 進行了 bis  加密。使用公共密鑰/私有密鑰進行簽名。
 
1)大致介紹:
LTPA Cookie 原始值 通過   3DES密鑰  使用 DESede/ECB/PKCS5P 進行加密。
此  3DES密鑰  也是采用 DESede/ECB/PKCS5P 進行加密,加密后再使用事先提供的   密鑰密碼 進行SHA-1 Hash,生成24個字節的密鑰,再進行Base64編碼。
 
如 Dmonio 里, LTPA Cookie 值為以下公式組成:
SHA-1=LTPA版本號+創建時間+過期時間+用戶名+Domino LTPA 密鑰
LTPA Cookie= Base64(LTPA版本號+創建時間+過期時間+用戶名+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+yzwcl722gHVMOnDZAW7U3jEay9Tk2yG4yXkMWU+617xndpVxke2jtS5wIyVVM3q7UDPw=

3)WebSphere LTPA Cookie 的解析

以下代碼為解析從 WebSphere 或 Domino 發送過來的 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個字節
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原理


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM