Files
build-web-application-with-…/6.4.md
2012-09-27 00:06:23 +08:00

75 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#6.4 预防session劫持
session劫持是一种比较严重的安全威胁也是一种广泛存在的威胁在session技术中客户端和服务端通过传送session的标识符来维护会话但这个标识符很容易就能被嗅探到从而被其他人利用这属于一种中间人攻击。
本部分通过一个实例来说明何为会话劫持通过这个实例读者其实更能理解session的本质。
##session劫持过程
我们写了如下的代码来展示一个count计数器
func count(w http.ResponseWriter, r *http.Request) {
sess := globalSessions.SessionStart(w, r)
ct := sess.Get("countnum")
if ct == nil {
sess.Set("countnum", 1)
} else {
sess.Set("countnum", (ct.(int) + 1))
}
t, _ := template.ParseFiles("count.gtpl")
w.Header().Set("Content-Type", "text/html")
t.Execute(w, sess.Get("countnum"))
}
count.gtpl的代码如下所示
Hi. Now count:{{.}}
然后我们在浏览器里面刷新可以看到如下代码:
![](images/6.4.hijack.png?raw=true)
不断刷新这个数字会不断的增长我们把他刷新到6我们打开chrome的cookie管理器可以看到如下的设置信息
![](images/6.4.cookie.png?raw=true)
下面是最关键的复制chrome地址栏里的地址然后打开另一个浏览器。这里我打开了firefox浏览器然后打开firefox的cookie模拟插件新建一个cookie把上图中cookie模拟到firefox如下图所示
![](images/6.4.setcookie.png?raw=true)
然后将地址粘贴到其地址栏里,回车后如下图:
![](images/6.4.hijacksuccess.png?raw=true)
我们看到我们换了浏览器但是我们获得了sessionID然后模拟了这个cookie存储的过程。这个例子是在同一台计算机上做的不过即使换用两台来做其结果也是一样的。此时如果交替点击两个浏览器里的链接你会发现他们其实操纵的是同一个计数器。其实不必惊讶此处firefox盗用了chrome和goserver之间的维持会话的钥匙即gosessionid这属于session hijack的一种。在goserver看来firefox交给了它一个gosessionid由于HTTP协议的无状态性它无法得知这个gosessionid是从chrome那里“劫持”来的它依然会去查找对应的session并执行相关计算。而此时chrome也无法得知自己的保持会话已经被“劫持”。
##session劫持防范
###cookieonly和token
我们通过上面session劫持的过程可以了解到session一旦被其他人劫持就非常危险黑客可以模拟用户行为进行很多非法操作。那么如何有效的来防止session劫持呢
其中一个解决方案就是值允许cookie设置然后设置cookie的httponly为true,这个属性是设置是否可通过客户端脚本访问这个设置的cookie第一这个可以防止这个cookie被XSS读取从而引起session劫持。
第二步就是在每个请求里面加上token类似前面章节里面讲的防止form重复递交类似的功能我们在每个请求里面加上一个隐藏的token然后每次验证这个token从而保证用户的请求都是唯一性。
###间隔生成新的SID
还有一个解决方案就是我们给session额外设置一个创建时间的值一旦过了一定的时间我们销毁这个sessionID重新生成新的session这样可以一定程度上防止session劫持的问题。
createtime := sess.Get("createtime")
if createtime == nil {
sess.Set("createtime", time.Now().Unix())
} else if (createtime.(int64) + 60) < (time.Now().Unix()) {
globalSessions.SessionDestroy(w, r)
sess = globalSessions.SessionStart(w, r)
}
session启动后我们设置了一个值用于记录生成sessionID的时间。通过每次请求判断是否过期(这里设置了60秒)定期生成新的ID这样使得攻击者获取有效sessionID的机会大大降低。
上面两个手段的组合可以在实践中消除session劫持的风险一方面 由于sessionID频繁改变使攻击者难有机会获取有效的sessionID另一方面因为sessionID只能在cookie中传递然后设置了httponly所以基于URL攻击的可能性为零同时被XSS获取sessionID也不可能。最后由于我们还设置了MaxAge=0这样就相当于session cookie不会留在浏览器的历史记录里面。
## links
* [目录](<preface.md>)
* 上一节: [session存储](<6.3.md>)
* 下一节: [小结](<6.5.md>)
## LastModified
* $Id$