一步步編寫PHP的Framework(十四)

來源:互聯網
上載者:User

 

 今天我說一下怎麼在架構中over掉這些安全問題。

      首先是SQL注入,這個如果你使用的是PDO,我覺得應該沒什麼問題,如果你使用的還是mysql_*等API,那麼你可以在架構中實現bindParameter或者在插入資料庫之前進行字串轉義。

      前兩天把上一篇文章寫完之後,Vian在後面留言說到過SQL注入的一個解決方案,就是在在插入DB之前進行'''.addslashes($id).''',它的意思就是首先進行addslashes操作,之後再強制單引號包裹,這樣它就是一個不折不扣的字串了,所以就注入不了,我覺得這個方法不錯,贊一個!!

      由於SQL注入需要聯絡到模型,XSS需要聯絡到視圖,這兩塊兒我都沒有開始講,所以我再後面再講怎麼在架構中解決,當然,如果我寫到後面忘記了,你也可以提醒我一下。

      上一次我講CSRF的時候,並沒有給出一個解決方案,今天我就給出這個解決方案。實際上解決的方法很簡單,就是給它產生一個隨機數,然後後端判定傳遞過來的數和正確的數是否吻合, 如果不吻合,就不執行相應的代碼了,這個隨機數我們稱為token。

      為了簡單,我們就將產生token和得到token的函數都寫在控制器中,即Controller.php。

      首先是產生隨機數,最簡單的方式是使用mt_rand()直接產生一個整數,但在這兒我使用之前我在initphp這個架構中看到的解決csrf的方法,在這兒,也謝謝initphp作者的思路:

      initphp的代碼是:

1 private function set_token() {
2         if (!$_COOKIE['init_token']) {
3             $str = substr(md5(time(). $this->get_useragent()), 5, 8);
4             setcookie("init_token", $str, NULL, '/');
5             $_COOKIE['init_token'] = $str; 
6         }
7     }

       為了簡單,我這兒就不使用userAgent了,initphp是將目前時間戳和userAgent拼接成字串之後再md5加密,取出第5到8位,我這邊的思路是將目前時間戳進行md5加密,然後從第0位開始取,取得的字串長度是隨機產生的:

1 $token = substr(md5(time()),0,mt_rand(10,15));

      為了防止隨機數太大或太小,我設定mt_rand的取值範圍為10到15,也就是說產生的token的位元為10到15位。

      產生token之後其他的事情就好辦了,當然,首先,也是設定token,我們沒有必要每次使用者請求的時候都產生一個隨機數,所以我們將它存放在COOKIE中,架構載入的時候會判定是否有token,如果沒有則動態產生一個,當然,產生的token會在一段時間之後到期失效,我這兒設定的時間為7天。

1 private function _setToken() {
2         if(empty($_COOKIE['_csrfToken'])) {
3             $token = substr(md5(time()),0,mt_rand(10,15));
4             $this->_token = $token;
5             setcookie('_csrfToken',$token,time() + 3600 * 24 * 7);
6         } else {
7             $this->_token = $_COOKIE['_csrfToken'];
8         }
9     }

 

      由於產生token的過程是架構自動完成的,所以沒有必要讓使用者看到此過程,所以將這個函數設為私人,然後在Controller類的建構函式中調用即可。

      剛才是產生token,那麼怎麼得到token呢,實際上得到token的方法就非常簡單了,就是一個簡單的getter:

1 protected function _getToken() {
2         return $this->_token;
3     }

      現在我再示範一下在使用者編寫的控制器的判定過程:

 

       假設使用者請求的URL是:http://localhost/index.php?c=Index&a=test&token=rwerdfdsfsdfs

       那麼這個控制器的類的代碼如下:

01 <?php
02 class IndexController extends Controller {
03     public function test() {
04         $token = empty($_GET['token']) ? '' : $_GET['token'];
05         if($token === $this->_getToken()) {
06             //判定為正常
07         } else {
08             $this->_redirect(array(
09                 //跳轉到某一個控制器的某一個Action
10             ));
11         }
12     }
13 }

        可能有人會問URl上面的token值是怎麼設定然後傳遞過來的呢?

        我們可以想一下,假設上一個頁面是Index控制器的test2這個Action,那麼我們可以在test2這個Action中首先使用$this->_getToken得到token值,然後在將資料傳遞到視圖,視圖中使用了之後,使用者點擊這個連結就可以將這個token值傳遞過來了。

         我現在提一個問題,假設使用者訪問A頁面的時候得到token,這個token還有兩秒就到期了,這個使用者三秒之後點擊這個含有token的連結到達B頁面,B頁面由於COOKIE中的token已經失效,所以重新產生一個token,然後再和傳遞的這個token比較,自然不匹配,然後就跳轉了,這還不是有問題的呢,那麼怎麼解決呢?

         由於還有一點時間,所以我提一下上傳檔案漏洞吧,使用者上傳一個比如test.php頁面,如果使用者沒有做檔案類型的判定,使用者上傳這個php檔案之後,按照連結訪問這個頁面,有可能這個頁面中有一些破壞性的代碼,整個網站就危險了。

          可能你已經在程式中判定了,只允許尾碼為jpg,png,gif這三種類型,那麼我可以將這個jsp頁面尾碼改成如jpg,上傳成功之後,如果網站存在某種漏洞能夠讓它修改檔案尾碼,那麼你的網站又危險了!!

          還假設你的網站不允許修改檔案尾碼名,但是它在上傳的圖片後面加上一段JS指令碼或者在上傳的檔案名稱上面寫一些指令碼,這些都可能很危險!!



相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.