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

來源:互聯網
上載者:User

 

上次講到控制器怎麼樣將資料傳遞到視圖,今天我就主要說一下在程式中怎麼讓代碼更“安全”,之後就轉到講模型,再講怎麼做視圖,最後再講控制器的功能強化。

      我再聲明一下,我寫這個文章只是讓大家對PHP的架構編寫有一個基本的瞭解,由於本人技術有限,這個文章是給PHP初學者學習的,所以高手勿噴,還有就是我現在時間也有限,所以每次可能需要兩三天才能寫一篇,每篇我寫的時間也要控制在一個小時以內,由於邊寫這個文章邊編代碼,所以代碼中可能會存在很多BUG,見諒!!

       如果你是一個PHP愛好者,請在文章後面積極回複一下,這種交流不僅可以使我的PHP技術提高,也鼓勵了我繼續寫下去的勇氣,謝謝!!

       很多人編寫PHP代碼什麼都不注意,遇到很多警告,就直接通過error_reporting屏蔽掉,這樣做我覺得問題是非常大的,比如:

1 <?php
2    $a = $_GET['a'];
1 echo $a;

      如果通過GET方式傳遞的參數有a,那麼程式非常正常,但是如果沒有傳遞呢,那就會拋出一個警告!!

      我的作法是首先將error_reporting設定為E_STRICT,不允許程式出現警告!!

      剛才這段代碼可能就需要修改成:

1 <?php
2 $a = isset($_GET['a']) ? $_GET['a'] : '';
1 echo $a;

       除了這種問題,還有就是PHP特有的 @符號 ,很多人都喜歡用這個來屏蔽錯誤,但是我覺得使用這個弊大於利,因為當項目很大的時候,出現一個錯誤,由於這個錯誤又被屏蔽,要找到這個錯誤的位置真心的很難!!

 

       關於異常的處理,雖然try catch會帶來很大的開銷,我個人覺得為了程式的健壯性,必要的try catch還是需要的。

       好吧,雜七雜八的說了這麼多,貌似這個和安全不太沾得上邊,但對於我來說,它們也是“安全”的一部分。

       現在假設你花費了十天時間編寫了一個簡單的部落格系統,購買了萬網的虛擬機器主機或VPS,申請網域名稱,網站備案,然後部署代碼,這一切的一切都搞定了,然後使用者就可以通過比如www.test.com這樣一個網域名稱來訪問你的部落格系統,你這套部落格系統很受歡迎,短時間內就積累了大量的人氣,但是突然有一天,你發現你的網站突然出故障了,你怎麼辦?

       線上上將PHP的設定檔中的error_reporting開啟,然後線上調試?

       說實話,我之前也在我的部落格系統上麵線上調試過,和上述情況不一樣的一點是,我的部落格訪問量很低,因為我這個人太懶了,不太喜歡去管理我的部落格。

        如果你的網站擁有很大的訪問量,你線上上做調試想想也是不可能的事情,那怎麼做呢?

        記Log,如果你的網站在發生故障之前你就有寫Log,那麼程式出現故障之後你只需要開啟記錄檔,然後就可以看到故障出現的位置,然後修複掉,這樣就OK了!!

        好了,現假設我是你的同學,並且也參與了你的部落格系統的開發,但是我和你前一陣鬧了一點矛盾,我懷恨在心,想把你的部落格系統破壞掉,怎麼破壞呢?

        首先假設你的資料庫名為Test,這個資料庫中存在一個user表,user表存放著20000個會員資訊,我知道你的部落格註冊系統的代碼是如下:

01 <?php
02 $username = $_POST['username'];
03 $password = $_POST['password'];
04 if(empty($username)  empty($password)) {
05      //跳轉到註冊介面並提示使用者名稱或密碼未填寫
06      exit();
07 }
08 //串連資料庫
09 //假設DB類封裝了很多SQL操作,析構的時候自動關閉資料庫連接,具體過程不寫了
10 //$db是一個資料庫DB類的執行個體,存在兩個方法
11 //$db->isUsernameExists判定是否使用者名稱是否存在
12 //$db->query 執行一條SQL語句
13 if(!$db->isUsernameExists($username)) {
14    $db->query("insert into user (username,password) values ('" . $username . "','" . $password. "')");
15    //設定session並跳轉
16    exit();
17 } else {
18     //跳轉到註冊介面並提示使用者名稱已存在
19     exit();
20 }

 

      這段代碼有問題嗎,我相信很多PHP Coder都會很鄙視的說到“你不就是想說SQL注入嘛”。

      的確,這個就是一個SQL注入的問題,這個問題已經很古老了,好像大家都知道,為什麼我還要講呢?

      這是因為我之前在學校看到過幾個由學弟編寫的PHP項目,他們就基本上沒有考慮過這個問題,很多代碼就直接這麼寫,當然,你如果按照網上SQL注入的方式去試,會發現你根本注入不了,貌似PHP已經自動幫你解決掉這個問題了,怎麼解決的呢,實際上就是對特殊字元前加上反斜線。

      首先說一下為什麼SQL注入失敗呢?如果你的php.ini中配置了自動轉義,PHP會在你將資料插入到DB之前對資料進行轉義。

      貌似這樣我們就不用考慮這個問題了,但是實際上PHP幫我們做了這些才讓事情更可怕,如果你將你的程式轉移到另外一台linux伺服器, 這台伺服器上面php.ini設定檔中配置了不自動進行轉義,那麼你的程式一下子問題就大了,我們不應該將我們代碼的安全性依賴於伺服器的配置。那麼怎麼搞定這個事情呢?

      幸好,PHP中已經有了addslashes函數,它會對特殊字元進行轉義,但是很遺憾,通過查看PHP手冊發現:

       預設情況下,PHP 指令 magic_quotes_gpc 為 on,它主要是對所有的 GET、POST 和 COOKIE 資料自動運行addslashes()。不要對已經被 magic_quotes_gpc 轉義過的字串使用 addslashes(),因為這樣會導致雙層轉義。遇到這種情況時可以使用函數 get_magic_quotes_gpc() 進行檢測

       那怎麼做呢,幸好PHP已經提供了一個get_magic_quotes_gpc函數可以來判定是否已經開啟了magic_quotes_gpc,所以我們可以自訂一個addslashes函數,如:

1 <?php
2 function myAddslashes($str) {
3     if(get_magic_quotes_gpc()){
4            return addslashes($str);
5     }
6 }

       其實還有另外的方法解決這個問題:

 

       1. 使用PDO來訪問DB,PDO中可以使用PDOStatement->bindParam,這樣,PDO會自動幫你做好這一切,並且我個人覺得PDO很有前途!!

       2. 如果get_magic_quotes_gpc為on,首先調用stripslashes去除逸出字元,然後在插入資料庫之前使用mysql_real_escape_string,我個人覺得這種方式比第一種方式靠譜!!

      當然,說了這麼多,有可能還有童鞋不知道什麼是SQL注入,我就簡略的講一下SQL注入的過程啊,熟悉SQL注入的人直接pass掉這一段。

      按照上面的例子,假設使用者在password這個欄位輸入的值為a');drop table user;...,那麼執行SQL的時候SQL語句就會變成:

          insert into user (username,password) values ('使用者名稱','a');drop table user;...')

     這個SQL首先會向user表插入一條記錄,然後刪除整個表,然後。。。。SQL出錯了。

     不過不管SQL是否出錯,user表已經沒有了,對於一個會員10000的部落格,使用者表沒有了,我覺得損失還是蠻大的,當然,你也可以將串連資料庫的使用者的許可權降低,沒有刪除表的許可權,但是這樣也不是一個治本的方法,還是解決掉SQL注入漏洞比較靠譜。

      好,解決掉SQL注入,我再說一下XSS(跨站指令碼漏洞)的問題。

      現有一段PHP的指令碼:

1 <?php
2 echo $_GET['a'];

      我才講到這個的代碼是有問題的,上面說的是有時候會拋出警告,但是如果傳遞參數的時候被不法分子利用,這個問題就大多了。

 

      現在假設訪問這個指令碼的URL是:http://localhost/test.php?a=a,我將參數a的值設為a,傳遞過去一點問題都沒有吧,但是現在假設我值換一下,URL變成了:

      http://localhost/test.php?a=<script>location.href="http://www.tmall.com"</script>,那麼執行指令碼的時候就會跳轉到天貓首頁,這樣恐怖吧!!

      如果這個不是跳轉到天貓,而是跳轉到某一個駭客設好的網址,他就可能將你的Cookie資訊弄到,然後就可以偽造Cookie,用你的身份登入部落格系統,然後。。。。你懂的。

      解決這個問題的方法也很簡單,就是字串轉義就OK,實際上就可以通過我們自訂的這個myAddslashes方法來做,調用了這個方法之後,指令碼無法執行了,但是有時候我們又需要執行指令碼,那怎麼做呢,我們可以對輸入的字串按照一定的規則過濾,具體怎麼使用的可以參照手冊。

      解決掉這個問題之後,我再說另外一個問題,這個問題就是CSRF(跨網站請求偽造漏洞),這是個什麼東東!!!

      現假設你有一個留言的系統,留言的內容是富文本的,使用者可以添加表情等等,表情的HTML代碼是<img src = "XXX" />,假設使用者填寫的表情是通過你提供的富文字編輯器來做的,沒有任何問題,但是如果他不使用這個,而是利用img標籤做了另外一個事情呢?

      怎麼做呢?很簡單的,就是改變img標籤的src屬性:

      <img src = "http://www.tmall.com" />

       提交留言之後發現這個圖片無法顯示,為什麼無法顯示其實也很簡單,根本不是一個合法的圖片連結,但是當一個不知情的使用者A查看留言的時候,會發生什麼情況,每次使用者開啟這個留言的頁面,實際上就會訪問www.tmall.com一次,如果將這個網址改成駭客的網址,那麼結果,還是你懂的。。。

        其實除了這些,還有上傳檔案的漏洞等等,由於時間有限,就不說了。

        我講這些實際上就是為了說明,安全問題實際上很重要,我們在編程式的時候要考慮的東西實際上是很多的。

        本來今天還要講怎麼在架構中怎麼去解決這些問題,但是又超出我預計的一個小時的時間了,那就下次再說了。



相關文章

Cloud Intelligence Leading the Digital Future

Alibaba Cloud ACtivate Online Conference, Nov. 20th & 21st, 2019 (UTC+08)

Register Now >

Starter Package

SSD Cloud server and data transfer for only $2.50 a month

Get Started >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

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

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