獲取網頁參數


實驗步驟一

 百度大家應該都用過,我們可以在百度查找一些想要了解的信息。但是我們需要告訴它,我們想要查找什么內容,這就需要我們告訴服務器我們需要查找與什么相關的內容,所以我們需要在搜索框輸入我們想要查找的信息的關鍵字,這里輸入的關鍵字就是給百度的服務器傳入參數(以后簡稱傳參),百度的服務器在接收了這個參數后,進行了一些處理,然后返回相關數據,比如我們輸入“網安實驗室”,百度就會給我們返回與“網安實驗室”相關度較高的網頁,如圖:

可以看到,輸入的關鍵字到了URL里面,像這種給服務器傳參的方法,就是HTTP協議中的GET方法,在GET方法中,查詢字符串(名稱/值)是在URL中發送的。其格式如下:

      /demo.php?name1=value1&name2=value2

      一般來說,只用來向服務器獲取信息,不向服務器傳敏感數據。

      要證明這是GET方法也很簡單,可以在網頁的任何位置鼠標右擊,然后選擇查看元素。

 

  然后點擊網絡。

 

 再點擊重新載入,瀏覽器會重新加載該頁面。

 此時會看到很多請求,每個請求都顯示了狀態碼(即狀態一欄)、請求方法、請求文件、請求域名、請求原因、請求類型等。

      在這些請求中,找到請求原因是document,請求類型是html的一行,這行就是搜索所發起的請求,后面的一些請求都是在請求完成后發起的,因為第一次請求完以后,有些如圖片瀏覽器需要重新拉取。

 在方法這一欄,可以看到都是GET,而且沒有POST方法,所以我們可以推斷我們給服務器傳參是通過GET的方式傳過去的。

      在狀態這一欄,有的可以看到狀態有的是200,有的是304,這是HTTP協議中的狀態碼。

      狀態代碼有三位數字組成,第一個數字定義了響應的類別,且有五種可能取值:

      1xx:指示信息--表示請求已接收,繼續處理

      2xx:成功--表示請求已被成功接收、理解、接受

      3xx:重定向--要完成請求必須進行更進一步的操作

      4xx:客戶端錯誤--請求有語法錯誤或請求無法實現

      5xx:服務器端錯誤--服務器未能實現合法的請求

      常見狀態代碼、狀態描述、說明:

      200 OK      //客戶端請求成功

      400 Bad Request  //客戶端請求有語法錯誤,不能被服務器所理解

      401 Unauthorized //請求未經授權,這個狀態代碼必須和WWW-Authenticate報頭域一起使用

      403 Forbidden  //服務器收到請求,但是拒絕提供服務

      404 Not Found  //請求資源不存在,eg:輸入了錯誤的URL

      500 Internal Server Error //服務器發生不可預期的錯誤

      503 Server Unavailable  //服務器當前不能處理客戶端的請求,一段時間后可能恢復正常

      在上圖中還可以看到304,304表示自從上次請求后,請求的網頁未修改過。服務器返回此響應時,不會返回網頁內容。

      如果網頁自請求者上次請求后再也沒有更改過應將服務器配置為返回此響應(稱為 If-Modified-Since HTTP 標頭)。服務器可以告訴瀏覽器自從上次訪問后網頁沒有變更,進而節省帶寬和開銷,同時提高用戶訪問速度,因為對於瀏覽器來說,它需要把所有的資源下載到本地渲染后展示出來。

      點擊上面說到的那個請求,一般會顯示在第一行,如果你做了其他操作導致有很多請求,可以先點擊左上角的垃圾桶的圖標,清空所有請求,再點擊一次重新載入。然后在右邊會顯示

      請求的詳細內容,點擊參數

 

 

  在這可以看到我們給百度服務器傳的參數,可以明顯看到我們給百度服務器傳的參數不止一個,在查詢字符串列表中,在冒號(:)左邊的是參數名,后面的是代表參數的值,在服務端,可以通過參數名來接收參數值,比如這里參數rsv_bp的值是1,所以在服務端,通過rsv_bp這個參數名,就能接收到1這個值,然后服務端再根據這個值做相應的處理,如果還有不懂的也沒關系,后面會詳細介紹。

      然后點擊消息頭,點擊編輯和重發。

然后就可以看到原始頭了。

   

 

 

可以看到,wd參數的值已經不是直接顯示中文字符,而是顯示%后面跟上一個16進制的數字,為什么會這樣呢?其實這是中文字符URL編碼后的值。

      雖然這里顯示的是我們輸入的字符,但是在發送給服務器的時候,瀏覽器會自動給中文字符URL編碼。為什么會這樣呢? 因為網絡標准RFC 1738做了硬性規定:“只有字母和數字[0-9a-zA-Z]、一些特殊符號"$-_.+!*'(),"[不包括雙引號]、以及某些保留字,才可以不經過編碼直接用於URL。”。

      一般來說,當我們向服務器請求資源的時候,都是用GET方法,不應該使用GET請求來發送一些敏感數據,如:賬號密碼,因為如果賬號密碼也被包含在url里面被發送的,很容易被人看見,而且,GET請求中的參數會被記錄在web日志中,如果有人通過惡意請求,可以讀web日志,那他將可以看見所有用戶的賬號密碼。

      我們來看下php是如何獲取用戶通過瀏覽器傳過去的參數的。

      在PHP里面,有許多預定義的變量都是“超全局的”,這代表他們在一個腳本的內部的任何地方都可以使用,即使實在函數或者方法中,要訪問這些“超全局變量”也無需使用global $var;這些超全局變量是:

      $GLOBALS

      $_SERVER

      $_GET

      $_POST

      $_FILES

      $_COOKIE

      $_SESSION

      $_REQUEST

      $_ENV

      本步驟中先了解$_GET。

      $_GET這個超全局變量是一個數組,它保存了通過 URL 參數傳遞給當前腳本的參數的值,也就是說,所有通過get方法傳過來的參數,都可以通過這個超全局變量來取得參數對應的值,要取得指定參數的值,可以通過參數名來索引$_GET這個數組。

      在實驗環境中,已經配置了sqli.com域名,現在通過代碼來看下如何獲取用戶傳過來的參數。在實驗環境中打開火狐瀏覽器,訪問sqli.com/get.php?id=12&name=admin。以后涉及到需要訪問sqli.com的步驟,都在試驗機中完成。

      這里的?表示從?后面開始是傳參數,當我們需要同時向服務器傳多個參數的時候,需要使用&來連接多個參數。這里代表往服務器傳了id、name這2個參數,值分別是12、admin。看代碼更能直觀地理解含義。該頁面源碼如下:

  

 

 它的作用僅僅只是輸出用戶通過get方法傳過來的id和name這2個參數的值。

 

 

 可以看到頁面輸出的就是我們傳過去的值,看別人的漏洞分析文章的時候,可能會經常看到說某某變量可控,在這里,我們通過GET方法傳過去的值就是可控的,可控指的是:我們可以控制某個變量的值。

      通過GET方法我們可以給服務器傳多個值,比如還可以在后面加一些參數。現在我們給該頁面傳一些其他參數,然后打印下這個全局變量。

      首先進入C:\wamp\www\sqli目錄,打開get.php,把前面輸出的代碼注釋掉(在英文輸入狀態下,在每行的最前面輸入2個 / 表示注釋掉這一行),把最后一行取消注釋。改完以后的代碼如圖:

      

      var_dump用來打印變量的相關信息,包括表達式的類型與值。

      然后訪問sqli.com/get.php?id=12&name=admin&user=test&home=dd,訪問后輸出如下圖:

 

 

  可以看到,該變量的類型是array,也就是數組。在“=>”左邊的是這個數組的鍵,右邊的是值。

      需要注意的是,我們傳過去的參數,服務器會原封不動地接受參數,如圖:

      

      如果我們傳過去的值里面有一些特殊字符,比如單引號、雙引號等服務端沒有任何處理,直接拼接sql語句的話,則會導致SQL注入、XSS等安全漏洞。想深入了解的可以學習“SQL注入原理與實踐”、“XSS跨站腳本攻擊原理與實踐”等實驗。

實驗步驟二

 

 除了上面講到的用GET方法給服務器傳參,還有一種常用的傳參方法,那就是POST。如果通過POST方法傳參,那么參數是在http請求的請求體中,並且是經過URL encode編碼的。

 

      在登錄的地方一般都是用POST方法,前面已經說過,如果包含敏感信息,就應該用POST方法。

 

      還是打開百度,點擊右上角的登錄,彈出登錄窗口:

 

 在輸入框中隨便輸入一些內容,如果需要驗證碼,需要輸入正確的驗證碼。

然后點擊登錄。

      

      提示輸入的賬號或密碼有誤,但是url並沒有改變,也就是說並沒有通過GET方法給服務器傳參數,那么服務器是如何知道我們輸入的賬號和密碼的呢?

      這里雖然沒有通過get方法傳參,但是它通過post方法給服務器傳參了。按F12或者鼠標右擊頁面選擇查看元素進入開發人員工具,進入網絡面板。再次輸入賬號密碼以及驗證碼,在點擊登錄之前點擊左上方的垃圾桶圖標清空內容

      點擊登錄。

      可以看到,第一個請求就是post請求。點擊post請求的這一行。會彈出這個請求的詳情。

      點擊編輯和重發。

      

      在請求主體中可以看到我們通過post方法提交的參數。你會發現里面多了很多參數。在這里是經過url編碼后的,看起來不方便,在參數這一欄看起來更方便。

      可以看到給服務器傳了很多參數,而我們輸入的只有2個,加上驗證碼也就三個參數,這說明百度自動帶入了一些其他參數,在里面可以看到username、password這2個參數,從參數名我們就可以猜出分別代表我們輸入的用戶名和密碼,但是輸入的密碼明明只有幾個字符,為什么到這里就變成了一串很長的毫無規律的字符串呢? 這說明我們輸入的密碼是被加密后才被發送百度服務器。

      那么PHP又是如何接受通過POST方法傳過去的參數的呢?

      還記得前面介紹的PHP中的超全局變量嗎?其中就有一個$_POST的超全局變量,它也是一個數組,它保存了用戶通過POST方法傳過去的參數。

 

 

關鍵代碼已經寫了注釋,頁面很簡單,獲取用戶的輸入內容然后原樣輸出到頁面,當然在實際開發中,不是這么簡單,一般都是獲取用戶的輸入后,保存到數據庫中,當然在保存之前還要先判斷該用戶是否已經注冊,如果數據庫中已經存在一個同樣的用戶名,則會提醒用戶該用戶已注冊。

      那么,又是如何得知數組的哪個鍵對應用戶輸入的輸入框呢? 仔細查看上面的html的代碼。

 每個輸入框都有個name屬性,我們可以通過這個name屬性的值來索引用戶的輸入框內容,比如,在用戶名的輸入框輸入:test,那么可以通過$_POST['username'] 來獲取該輸入框的值,也就是說,$_POST['username']的值為test。

      可能細心的朋友已經看出來了,這明明是一個php頁面,怎么也可以寫html代碼呢? 因為在php文件中,php 解釋器只有在遇到 <?php 的時候,才開始把后面的代碼當成php代碼處理,不在<?php ?>內的代碼不處理,直接原樣輸出。<?php 是php的開始標記,告訴php解釋器,在遇到結束標記前,都是php的代碼。?> 是 php的結束標記。

 瀏覽器打開訪問http://sqli.com/post.php.

 

 

為了更方便地了解post傳參的位置,我們使用抓包工具來抓包,抓包工具通過修改瀏覽器代理的方法,來攔截瀏覽器發送的數據包,攔截數據包以后,可以進行修改數據包,丟棄數據包等操作。

      機器已經安裝好fiddler,點擊桌面fiddler圖標打開fiddler。

      然后進入瀏覽器設置。

 

 進入瀏覽器代理設置頁面。

 

 

選擇使用系統代理設置,點擊確認。

      

 

  重新訪問http://sqli.com/post.php,此時可以在fiddler看到我們剛才的請求,由於我們沒有設置攔截請求,所以默認直接允許請求了。

 

  還有其他不相關的一些請求,可以不用管。點擊這個請求,查看這個請求的原始請求。

      

      如果你是重新輸入的url訪問,或者之前沒有點擊提交,那么你可以看到這個請求是get請求而不是post,其中紅框標記中的內容為http請求頭。

      

      其中第一行的GET說明這次請求是GET請求,后面的url表示本次請求的路徑,最后面的HTTP/1.1說明HTTP 1.1版本。

      由於我們沒有在頁面的輸入框中填內容,所以該請求是GET請求,如果在輸入框中填了內容,那么請求方式就會變成POST。

      

      內容隨便,填好以后先不點提交,在fiddler中,發現有多余的請求

      

      先把這些請求清空掉。點擊上方的X,然后選擇remove_all。

      

      就會清空所有記錄,然后再點擊提交。

      

      可以看到,頁面輸入了我們輸入的內容,同時fiddler中,也顯示了我們本次請求,點擊這個請求,查看該請求詳情,同樣來到raw的界面查看原始的http請求。

      

      可以看到,請求方法變成了POST,此時,在下方,比上次GET請求明顯多了一些數據。

      

      這些數據就是我們通過POST方法傳給服務器的參數,這些數據所在的位置就是HTTP請求體中,HTTP請求頭和HTTP請求體用空行分割。

      同樣的,POST請求的數據,也需要經過url編碼,可以在頁面輸入中文測試,填寫如下內容:

      

      點擊提交后,來到fiddler查看這次請求的POST參數。

      

      很明顯的經過了URL編碼,服務器在接受這些參數值的時候,會自動URL解碼。所以輸出的字符還是我們在輸入框中輸入的內容。

      同樣,如果服務端在接受用戶輸入的參數后,沒有進行處理,就直接拼接SQL語句進行查詢就可能會引起安全漏洞,比如最常見的SQL注入和XSS。原理可以參考“SQL注入原理與實踐”、“XSS跨站腳本攻擊原理與實踐”等實驗。

      通過前面的實驗,可以知道,GET方法和POST方法的區別,主要就是傳參的地方不同,GET方法通過URL傳參,POST方法在請求體中傳參。在實際應用中,GET方法多用來向服務器發起請求獲取資源,而POST方法多用在需要修改資源的地方,以及一些敏感信息使用POST方法,並沒有什么規范強制要求在登錄處使用POST方法。但是我們應該使用POST方法而不用GET方法,因為POST方法相對來說,比GET方法私密,因為參數不會顯示URL而在請求體中,用戶看不到請求體。有些請求必須使用POST方法。比如向服務器傳文件等。因為服務器明確規定要求使用POST方法。 

 


免責聲明!

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



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