知乎專欄 | 多維度架構 | 微信號 netkiller-ebook | QQ群:128659835 請註明“讀者” |
應用防火牆我提供了一個思路,不便提供代碼。
下面的代碼是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();
權限來自下面數組數據,這裡僅僅提供一個例子,管理權限你可以單獨實現一個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) 用戶判斷權限是否合法。
這裡提供了一個 News 類,用於演示怎樣控制每個function的權限。
同時還提供了一個簡單的 Logging 類用於記錄程序運行日誌。
有了上面的例子就可以將News應用於SOAP一類Web Service上,用來控制每個方法的權限
上面僅僅對於方法控制權限,接下來我們為程序增加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('*'));