主要防止非法用户修改cookie信息,以及cookie的超时时间
传统cookie存储,Cookie(name, value),value很容易就被篡改。
防修改cookie存储,Cookie(name, value+“&&”+ signToken+“&&”+saveTime+“&&”+maxTime)
signToken :签名密钥 由md5(value+saveTime+maxTime+”自定义密钥“)生成
saveTime:cookie创建时间
maxTime:cookie超时时间
设置Cookie
public static void put(HttpServletResponse response, String key, String value, int maxTime) {
String pwdKey = "white_yu"; //自定义密钥
String saveTime = System.currentTimeMillis() + "";
String signToken = md5(pwdKey, saveTime, maxTime + "", value);
String cookieValue = signToken + "&&" + saveTime + "&&" + maxTime
+ "&&" + value;
Cookie cookie = new Cookie(key,cookieValue);
cookie.setMaxAge(maxTime);
response.addCookie(cookie);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
获取Cookie
public static String getCookie(String cookieValue) {
String pwdKey = "white_yu"; //自定义密钥
if (StringUtils.isNotBlank(cookieValue)) {
String cookieStrings[] = cookieValue.split("&&");
if (null != cookieStrings && 4 == cookieStrings.length) {
String signToken = cookieStrings[0];
String saveTime = cookieStrings[1];
String maxTime = cookieStrings[2];
String value = cookieStrings[3];
String sign = md5(pwdKey, saveTime, maxTime, value);
// 保证 cookie 不被人为修改
if (sign.equals(signToken)) {
long stime = Long.parseLong(saveTime);
long maxtime = Long.parseLong(maxTime) * 1000;
// 查看是否过时
if ((stime + maxtime) - System.currentTimeMillis() > 0) {
return value;
}
}
}
}
return null;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
版权声明:转载请标注原文地址 https://blog.csdn.net/soul_code/article/details/52768421
cookie是存储在用户本地的,最高权限还是在用户手上,服务器可以验证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
- 过期时间
- 签名信息,如:
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原理