完成了第四第五小节
This commit is contained in:
57
6.4.md
57
6.4.md
@@ -3,10 +3,67 @@ 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:{{.}}
|
||||
|
||||
然后我们在浏览器里面刷新可以看到如下代码:
|
||||
|
||||

|
||||
|
||||
不断刷新这个数字会不断的增长,我们把他刷新到6,我们打开chrome的cookie管理器,可以看到如下的设置信息:
|
||||
|
||||
|
||||

|
||||
|
||||
下面是最关键的,复制chrome地址栏里的地址,然后打开另一个浏览器。这里我打开了firefox浏览器,然后打开firefox的cookie模拟插件,新建一个cookie,把上图中cookie模拟到firefox,如下图所示
|
||||
|
||||

|
||||
|
||||
然后将地址粘贴到其地址栏里,回车后如下图:
|
||||
|
||||

|
||||
|
||||
我们看到我们换了浏览器,但是我们获得了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(sess.SessionID())
|
||||
sess = globalSessions.SessionStart(w, r)
|
||||
}
|
||||
|
||||
session启动后,我们设置了一个值,用于记录生成sessionID的时间。通过每次请求判断是否过期(这里设置了60秒)定期生成新的ID,这样使得攻击者获取有效sessionID的机会大大降低。
|
||||
|
||||
上面两个手段的组合可以在实践中消除session劫持的风险,一方面, 由于sessionID频繁改变,使攻击者难有机会获取有效的sessionID;另一方面,因为sessionID只能在cookie中传递,然后设置了httponly,所以基于URL攻击的可能性为零,同时被XSS获取sessionID也不可能。最后,由于我们还设置了MaxAge=0,这样就相当于session cookie不会留在浏览器的历史记录里面。
|
||||
|
||||
|
||||
## links
|
||||
|
||||
1
6.5.md
1
6.5.md
@@ -1,4 +1,5 @@
|
||||
#6.5 小结
|
||||
这章我们学习了什么是session,什么是cookie,以及他们两者之间的关系。但是目前Go官方标准包里面不支持session,所以我们设计了一个session管理器,实现了session从创建到销毁的整个过程。然后定义了Provider的接口,使得可以支持各种后端的session存储,然后我们在第三小节里面介绍了如何使用内存存储来实现session的管理。第四小节我们讲解了session劫持的过程,以及我们如何有效的来防止session劫持。通过这一章的讲解,希望能够让读者了解整个sesison的执行原理以及如何实现,而且是如何更加安全的使用session。
|
||||
## links
|
||||
* [目录](<preface.md>)
|
||||
* 上一节: [session存储](<6.4.md>)
|
||||
|
||||
BIN
images/6.4.cookie.png
Normal file
BIN
images/6.4.cookie.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 69 KiB |
BIN
images/6.4.hijack.png
Normal file
BIN
images/6.4.hijack.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
BIN
images/6.4.hijacksuccess.png
Normal file
BIN
images/6.4.hijacksuccess.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
BIN
images/6.4.setcookie.png
Normal file
BIN
images/6.4.setcookie.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
Reference in New Issue
Block a user