Home | 簡體中文 | 繁體中文 | 雜文 | 知乎專欄 | Github | OSChina 博客 | 雲社區 | 雲棲社區 | Facebook | Linkedin | 視頻教程 | 打賞(Donations) | About
知乎專欄多維度架構 微信號 netkiller-ebook | QQ群:128659835 請註明“讀者”

15.3. 簡單實現

應用防火牆我提供了一個思路,不便提供代碼。

下面的代碼是10年前寫的,沒有100%實現,因為該代碼不會影響競業,供大家參考。

	
<?php
/* 
* =====================================
* Website: http://netkiller.github.com
* Author: neo <netkiller@msn.com>
* Email: netkiller@msn.com
* =====================================
*/

class Logging {
	protected $file;
	public function __construct($logfile = "/tmp/debug.log"){
		$this->file = fopen($logfile,"a+");
	}
	public function __destruct() {
        //fclose($this->file);
    }
	public function close() {
        fclose($this->file);
    }
	private function write($msg){
			fwrite($this->file,date('Y-m-d H:i:s').' '.$msg."\r\n");
	}
	public function info($msg){
		$this->write(__FUNCTION__.' '.$msg);
	}
	public function warning($msg){
		$this->write(__FUNCTION__.' '.$msg);
	}
	public function error($msg){
		$this->write(__FUNCTION__.' '.$msg);
	}
	public function debug($msg){
		$this->write(__FUNCTION__.' '.$msg);
	}
	
}

class Permission{
	protected $_PERMISSION = array();
	
	public function __construct($login){
		$test = 
		array(
			'neo' => array(
				'News'=> array(
					'add' => 'Y',
					'remove' => 'N',
					'update' => 'Y'
					),
				'RSS'=> array(
					'add' => 'Y',
					'remove' => 'N',
					'update' => 'Y'
					)
				),
			'jam' => array(
				'News'=> array(
					'add' => 'Y',
					'remove' => 'N',
					'update' => 'Y'
					),
				'RSS'=> array(
					'add' => 'Y',
					'remove' => 'N',
					'update' => 'Y'
					)
				)				
		);
		//print_r($test);
		$this->load($test[$login]);
	}
	public function load($arr){
		$this->_PERMISSION = $arr;
	}

	public function is_allowed($class, $fun){
		$class 	= trim($class);
		$fun 	= trim($fun);
		//echo $class, $fun;
		//print_r($this->_PERMISSION);
		if(array_key_exists($class,$this->_PERMISSION)){
			if(array_key_exists($fun,$this->_PERMISSION[$class])){
				if($this->_PERMISSION[$class][$fun] == 'Y') return true;
				//return in_array("Y",$this->_PERMISSION[$class][$fun]);
			}
		}
		return false;
	}
	public function is_denied($class, $fun){
		return (!$this->is_allowed($class, $fun));
	}	
	public function scan(){
		return true;
	}
}

class News extends Permission{

	private $logging;
	public function __construct(){
		parent::__construct('neo');
		$this->logging = new Logging('/tmp/news.log');
	}
	public function __destruct() {
		$this->logging->debug('news->get permission denied!!!');
		$this->logging->close();
    }
	public function add(){
		if(!$this->is_allowed(__CLASS__,__FUNCTION__)) return;
		print("Allowed!!! \r\n");
		$this->logging->info('news->add ok');
	}
	public function get(){
		if( $this->is_denied(__CLASS__,__FUNCTION__)) {
			print("Denied!!! \r\n");
			$this->logging->warning('news->get permission denied!!!');
		}
		
	}
}



$news = new News();
$news->add();
$news->get();
	
	
		

15.3.1. 權限控制與實現

權限來自下面數組數據,這裡僅僅提供一個例子,管理權限你可以單獨實現一個class,實現供權限管理功能,最終後轉化為下面的資料結構即可。例如你可以將權限寫入資料庫,最終拼裝如下數字讓Permission順利load即可。

		
array(
			'neo' => array(
				'News'=> array(
					'add' => 'Y',
					'remove' => 'N',
					'update' => 'Y'
					),
				'RSS'=> array(
					'add' => 'Y',
					'remove' => 'N',
					'update' => 'Y'
					)
				),
			'jam' => array(
				'News'=> array(
					'add' => 'Y',
					'remove' => 'N',
					'update' => 'Y'
					),
				'RSS'=> array(
					'add' => 'Y',
					'remove' => 'N',
					'update' => 'Y'
					)
				)				
		);		
		
			

public function is_allowed($class, $fun) 用戶判斷權限是否合法。

15.3.2. 演示

這裡提供了一個 News 類,用於演示怎樣控制每個function的權限。

同時還提供了一個簡單的 Logging 類用於記錄程序運行日誌。

有了上面的例子就可以將News應用於SOAP一類Web Service上,用來控制每個方法的權限

15.3.3. 增加7 Layer防火牆

上面僅僅對於方法控制權限,接下來我們為程序增加7層防火牆功能

		
<?php
/* 
* =====================================
* Website: http://netkiller.github.com
* Author: neo <netkiller@msn.com>
* Email: netkiller@msn.com
* =====================================
*/
class Firewall{

	protected $status;
	protected $policy;
	protected $chain;
	protected $rule;
	protected $match;
	private $debug;
	//$get,$post,$cookie,$server;

	public function __construct() {
		$this->name 	= "Firewall";
	}

	public function __destruct() {
		//print "Destroying " . $this->name . "\n";
	}
	
	public function enable(){
		$this->status = true;
	}
	public function disable(){
		$this->status = false;
	}
	
	public function get(){
		if($this->status){
			$this->chain 	= $_GET;
			return($this);
		}else{
			return($this->status);
		}			
	}
	
	public function post(){
		if($this->status){
			$this->chain 	= $_GET;
			return($this);
		}else{
			return($this->status);
		}
		$this->chain 	= $_POST;
	}
	
	public function cookie() {
		if($this->status){
			$this->chain = $_COOKIE;
			return($this);
		}else{
			return($this->status);
		}
		
	}
	
	public function server(){
		if($this->status){
			$this->chain = $_SERVER;
			return($this);
		}else{
			return($this->status);
		}
	}
	
	public function match($key, $value){
		if($this->debug) print_r($this->chain);
		$this->match = false;
		if(!array_key_exists($this->chain, $key)){
			if($this->chain[$key] == $value){
				$this->match = true;	
			}
		}
		return($this);
	}
	public function policy($p){
		$this->policy = $p;
	}
	public function counter($tm, $cnt){
		return($this);
	}
	public function allow($fun = null){
		if($this->status && $this->match){
			if($fun){
				$fun();
			}
		}
		$this->destroy();
		return($this->status);
	}
	public function deny($fun = null){
		if($this->status && $this->match){
			if($fun){
				$fun();
			}
		}
		$this->destroy();
		return($this->status);
	}
	public function debug($tmp){
		$this->debug = $tmp;
	}
	public function ip($ipaddr){
		return $this->server()->match('REMOTE_ADDR', $ipaddr);
	}
	public function destroy(){
		$this->chain = array();
		$this->match = false;
	}
};

#include_once('firewall.php')
$fw = new Firewall();

$fw->debug(true);
$fw->debug(false);
$fw->enable();
//$fw->disable();
function test(){
	echo 'OK';
};
function allow(){
	echo 'allow';
};
function deny(){
	echo 'deny';
};
//$fw->policy('blacklist');

$fw->ip('192.168.3.17')->allow('allow');
$fw->ip('192.168.3.17')->deny('deny');

$fw->counter('1m',5)->match('id','1000')->deny('test');

/*
$fw->ip('172.16.0.0/24')->allow();
$fw->ip('172.16.0.0','255.255.255.0')->allow();

$fw->header(array('User-Agent' => 'MSIE5'))->deny()
*/
$fw->get()->match('id','1000')->deny('test');
$fw->get()->match('name','chen')->allow('test');
//$fw->get()->match(array('id' => '1000'))->deny();
/*
$fw->post()->data(array('action'=>'/login.php'))->allow()
$fw->cookie()->data(array('userid'=>'test'))->deny()
*/
$fw->server()->match('HTTP_REFERER', 'http://www.mydomain.com/index.html')->allow('test');
$fw->server()->match('REQUEST_METHOD', 'GET')->deny('test');

$fw->disable();
//$fw->destroy();
		
			

這裡僅僅給你一個思路,我並沒有寫完程序。例如控制IP請求次數可以如下實現,請自行改善程序

		
<?php
/* 
* =====================================
* Website: http://netkiller.github.com
* Author: neo <netkiller@msn.com>
* Email: netkiller@msn.com
* =====================================
*/
require 'SharedConfigurations.php';

$single_server = array(
    'host'     => '127.0.0.1',
    'port'     => 6379,
    'database' => 0
);

$multiple_servers = array(
    array(
       'host'     => '127.0.0.1',
       'port'     => 6379,
       'database' => 15,
       'alias'    => 'first',
    ),
    array(
       'host'     => '127.0.0.1',
       'port'     => 6380,
       'database' => 15,
       'alias'    => 'second',
    ),
);


$client = new Predis\Client($single_server, array('prefix' => 'fw:'));

$key=$_SERVER['REMOTE_ADDR'];

if(!$client->exists($key)){
	$client->setex($key, 20, 1);
}else{
	$client->incrby($key,1);
}

$counter = $client->get($key);

if($counter > 10){
	echo 'Deny';
}

print_r($client->get($key));

//var_dump($client->keys('*'));