2012
Nov
13

網頁好讀版


一個網站的最基本功能,通常會是會員系統,而會員系統也算是一項重要的功能,因為這裡面包含的個人隱私與帳號、密碼,一旦會員系統被駭客入侵,User 對網站的信任度也就會大幅下降,接著這篇文章將會介紹一些「登入程式邏輯」上的錯誤,造成系統的漏洞。

登入驗證順序錯誤

登入驗證一定要在程式的最開端進行,而不能放在程式的中段,或是後段,曾經看過有工程師,將修改會員資料的邏輯處理,寫在登入驗證的前面。

updateMember.php 有問題的登入驗證範例
  1. <?php
  2. updateMember($_POST['name']);
  3. if(!login()){
  4. echo '<script>alert("您尚未登入")</script>';
  5. exit(1);
  6. }
  7. ?>

上述的程式中,會先更新會員資料,然後再去驗證會員是否有登入,而駭客只要將 data post updateMember.php , Php 程式就會先更新會員資料,接著彈出錯誤訊息給 User,因為順序上的錯誤,造成駭客可以修改會員資料,甚至修改管理員的密碼,而入侵整個網站。

登入驗證失敗後,未中斷程式

當會員登入驗證失敗後,必需重導頁面到登入畫面,並且中斷程式的運行,否則程式會繼續執行,直到結束。

updateMember2-1.php 未中斷程式運行範例
  1. <?php
  2. if(!login($account, $passwd)){
  3. echo '<script>confirm("你並非管理員,不可修改會員資料")</script>';
  4. }
  5. updateMember($_POST['name']);
  6. ?>

在範例 2-1 中,當驗證登入失敗後,會回傳一段 javascript ,告知 user 並非登入中。

updateMember2-2.php 未中斷程式運行範例
  1. <?php
  2. if(!login($account, $passwd)){
  3. header("location:login.php");
  4. }
  5. updateMember($_POST['name']);
  6. ?>

在範例 2-2 中,當驗證登入失敗後,會直接回傳 http header ,告知 Browser重導到登入頁。

這兩個範例,雖然都有回傳訊息給 user,告知無法修改會員資料,但是卻漏掉 「exit(1)」中斷程式的運行,駭客就可以不需要登入,而修改會員 or 管理員資料,入侵系統。

未對所有功能進行登入驗證

「所有需要會員登入才能運作的功能,都要加上登入驗證」,這句話看起沒有大不了,大家也都知道,但是沒有網路安全觀念的工程師們,還是常常會寫出漏掉驗證的程式碼。

index3-1.php 網站全部功能的入口頁
  1. <?php
  2. if(!login($account, $passwd)){
  3. header("location:login.php");
  4. exit(1);
  5. }
  6. if($_POST['action'] == "updateMember") {
  7. require "updateMember3-2.php"; //更新會員資料
  8. }
  9. ?>
updateMember3-2.php 更新會員資料的 php file
  1. <?php
  2. updateMember($_POST['name']);
  3. ?>

有些工程師會將網站功能的入口都作在同一個 url 上,例如透過 index3-1.php 這一個頁面,當傳入的參數 action = updateMember ,就自動載入 updateMember3-2.php 並且完成會員更新的行為,因為 index3-1.php 這個檔案的開頭就已經先驗證會員登入狀態,所以工程師就會以為這個程式非常安全。

其實駭客只要直接將參數傳給 updateMember3-2.php 這個 url ,跳過 index3-1.php ,就能輕易的再一次修改會員資料。

會員登入使用的 cookie 需加密

一般在會員登入之後,網站會建立一個代表這位會員已經登入過的 cookie 記錄,有了這個記錄,網站才知道這位會員不用再登入第二次,他可以執行會員應有的功能。

因為 cookie 是直接存在 Browser 裡面,駭客可以輕易的看到 cookie 的格式是什麼,所以我們還必需對 cookie 加密。

login4-1.php 會員登入頁,錯誤的儲存 cookie
  1. <?php
  2. if(login($_POST['account'], $_POST['password']){
  3. setcookie("member", base64_encode($_POST['account']));
  4. }
  5.  
  6. ?>

有不少工程師只會簡單的對 cookie 做 base64 encode,這個加密出來的格式,很容易被駭客看出來,解密也相對簡單,例如 「password」 base64 encode 過後的代碼是 「cGFzc3dvcmQ=」,只要使用 base64_decode ,就能馬上破解出來。

另外登入的 cookie 最好要加上後端程式能夠判定的使用期限,再經過一段時間後,cookie 就不能再被使用,就算有駭客故意使用過期的 cookie,程式也要能過瀘掉,為了這個功能,通常會在 cookie 的內容加入登入時間。

一個最基本的登入 cookie ,至少要會員密碼,加上一個網站專用的固定 key,組合這二個數值,並且使用 md5 加密儲存,而 key 也要三不五時的變換一下。

login4-2.php 一種正確的 cookie 加密方式
  1. <?php
  2. if(login($_POST['account'], $_POST['password']){
  3. $val = mcrypt_encrypt($cipher, $key, $_POST['account'].$expiredTime, $mode);
  4. $val .= md5($_POST['password'].$key);
  5. setcookie("member", $val);
  6. }
  7.  
  8. ?>
md5 只能算是最普通的加密方式,如果想要更好的安全機制,可以考慮其他的 Encrypt Library。

網頁好讀版