用PHP構建一個簡易監視引擎

來源:互聯網
上載者:User

摘要:在本文中,讓我們共同探討基於PHP語言構建一個基本的伺服器端監視引擎的諸多技巧及注重事項,並給出完整的源碼實現。

  一. 更改工作目錄的問題

  當你編寫一個監視程式時,讓它設定自己的工作目錄通常更好些。這樣以來,假如你使用一個相對路徑讀寫檔案,那麼,它會根據情況自動處理使用者期望存放檔案的位置。總是限制程式中使用的路徑儘管是一種良好的實踐;但是,卻失去了應有的靈活性。因此,改變你的工作目錄的最安全的方法是,既使用chdir()也使用chroot()。

  chroot()可用於PHP的CLI和CGI版本中,但是卻要求程式以根許可權運行。chroot()實際上把當前進程的路徑從根目錄改變到指定的目錄。這使得當前進程只能執行存在於該目錄下的檔案。經常情況下,chroot()由伺服器作為一個"安全裝置"使用以確保惡意代碼不會修改一個特定的目錄之外的檔案。請牢記,儘管chroot()能夠阻止你訪問你的新目錄之外的任何檔案,但是,任何當前開啟的檔案資源仍然能夠被存取。例如,下列代碼能夠開啟一個記錄檔,調用chroot()並切換到一個資料目錄;然後,仍然能夠成功地登入並進而開啟檔案資源:

<?php
$logfile = fopen("/var/log/chroot.log", "w");
chroot("/Users/george");
fputs($logfile, "Hello From Inside The Chrootn");
?>

  假如一個應用程式不能使用chroot(),那麼你可以調用chdir()來設定工作目錄。例如,當代碼需要載入特定的代碼(這些代碼能夠在系統的任何地方被定位時),這是很有用的。注重,chdir()沒有提供安全機制來防止開啟未授權的檔案。

  二. 放棄特權

  當編寫Unix精靈時,一種經典的安全預防措施是讓它們放棄所有不需要的特權;否則,擁有不需要的特權輕易招致不必要的麻煩。在代碼(或PHP本身)中含有漏洞的情況下,通過確保一個精靈以最小許可權使用者身份運行,往往能夠使損失減到最小。

  一種實現此目的的方法是,以非特權使用者身份執行該精靈。然而,假如程式需要在一開始就開啟非特權使用者無權開啟的資源(例如記錄檔,資料檔案,通訊端,等等)的話,這通常是不夠的。

  假如你以根使用者身份運行,那麼你能夠藉助於posix_setuid()和posiz_setgid()函數來放棄你的特權。下面的樣本把當前運行程式的特權改變為使用者nobody所擁有的那些許可權:

$pw=posix_getpwnam('nobody');
posix_setuid($pw['uid']);
posix_setgid($pw['gid']);

  就象chroot()一樣,任何在放棄特權之前被開啟的特權資源都會保持為開啟,但是不能建立新的資源。

  三. 保證排它性

  你可能經常想實現:一個指令碼在任何時刻僅運行一個執行個體。為了保護指令碼,這是非凡重要的,因為在後台運行輕易導致偶然情況下調用多個執行個體。

  保證這種排它性的標準技術是,通過使用flock()來讓指令碼鎖定一個特定的檔案(經常是一個加鎖檔案,並且被排它式使用)。假如鎖定失敗,該指令碼應該輸出一個錯誤並退出。下面是一個樣本:

$fp=fopen("/tmp/.lockfile","a");
if(!$fp || !flock($fp, LOCK_EX | LOCK_NB)) {
 fputs(STDERR, "Failed to acquire lockn");
 exit;
}
/*成功鎖定以安全地執行工作*/


  注重,有關鎖機制的討論涉及較多內容,在此不多加解釋。

四. 構建監視服務

  在這一節中,我們將使用PHP來編寫一個基本的監視引擎。因為你不會事Crowdsourced Security Testing道怎樣改變,所以你應該使它的實現既靈活又具可能性。
該記錄程式應該能夠支援任意的服務檢查(例如,HTTP和FTP服務)並且能夠以任意方式(通過電子郵件,輸出到一個記錄檔,等等)記錄事件。你當然想讓它以一個精靈方式運行;所以,你應該請求它輸出其完整的目前狀態。

  一個服務需要實現下列抽象類別:

abstract class ServiceCheck {
 const FAILURE = 0;
 const SUCCESS = 1;
 protected $timeout = 30;
 protected $next_attempt;
 protected $current_status = ServiceCheck::SUCCESS;
 protected $previous_status = ServiceCheck::SUCCESS;
 protected $frequency = 30;
 protected $description;
 protected $consecutive_failures = 0;
 protected $status_time;
 protected $failure_time;
 protected $loggers = array();
 abstract public function __construct($params);
 public function __call($name, $args)
 {
  if(isset($this->$name)) {
   return $this->$name;
  }
 }
 public function set_next_attempt()
 {
  $this->next_attempt = time() $this->frequency;
 }
 public abstract function run();
 public function post_run($status)
 {
  if($status !== $this->current_status) {
   $this->previous_status = $this->current_status;
  }
  if($status === self::FAILURE) {
   if( $this->current_status === self::FAILURE ) {
    $this->consecutive_failures ;
   }
   else {
    $this->failure_time = time();
   }
  }
  else {
   $this->consecutive_failures = 0;
  }
  $this->status_time = time();
  $this->current_status = $status;
  $this->log_service_event();
 }
 public function log_current_status()
 {
  foreach($this->loggers as $logger) {
   $logger->log_current_status($this);
  }
 }
 private function log_service_event()
 {
  foreach($this->loggers as $logger) {
   $logger->log_service_event($this);
  }
 }
 public function register_logger(ServiceLogger $logger)
 {
  $this->loggers[] = $logger;
 }
}

  上面的__call()重載方法提供對一個ServiceCheck對象的參數的唯讀存取操作:

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.