月度归档:2010年06月

Nginx虚拟主机防Webshell安全检测程序完美版(图)[转]

作者:Rainy fox   来源:http://www.key0.cn/

我们先来看下nginx.conf

  server
  {
    listen       80;
    server_name  www.a.com;
    index index.html index.htm index.php;
    root  /data/htdocs/www.a.com/;

    #limit_conn   crawler  20;   
                            
    location ~ .*\.(php|php5)?
    {     
      #fastcgi_pass  unix:/tmp/php-cgi.sock;
      fastcgi_pass  127.0.0.1:9000;
      fastcgi_index index.php;
      include fcgi.conf;
    }

}

  server
  {
    listen       80;
    server_name  www.b.com;
    index index.html index.htm index.php;
    root  /data/htdocs/www.b.com/;

    #limit_conn   crawler  20;   
                            
    location ~ .*\.(php|php5)?
    {     
      #fastcgi_pass  unix:/tmp/php-cgi.sock;
      fastcgi_pass  127.0.0.1:9000;
      fastcgi_index index.php;
      include fcgi.conf;
    }

}

nginx在80端口接受到访问请求后,会把请求转发给9000端口的php-cgi进行处理

而如果修改php.ini中open_basedir= ../../../../../ ,针对两个不同的网站,www.a.com , www.b.com都会把请求发送给9000处理,而如果先访问www.a.com那么../../../../../就会变成A网站的根目录地址,然后这时候如果你访问www.b.com,那么open_basedir仍然是A网站的根目录,但是对于B来说,又是不允许访问的,所以就造成了,第二个站点打开以后会出现no input files,那么有什么解决办法呢?

我们可以把不同的虚拟主机发送到不同的php-cgi端口进行处理,当然响应的php-fpm配置文件中的open_basedir也不同。。我们来看看怎么配置。。

首先,nginx.conf配置如下

 server
  {
    listen       80;
    server_name  www.a.com;
    index index.html index.htm index.php;
    root  /data/htdocs/www.a.com/;

    #limit_conn   crawler  20;   
                            
    location ~ .*\.(php|php5)?
    {     
      #fastcgi_pass  unix:/tmp/php-cgi.sock;
      fastcgi_pass  127.0.0.1:9000;
      fastcgi_index index.php;
      include fcgi.conf;
    }

}

  server
  {
    listen       80;
    server_name  www.b.com;
    index index.html index.htm index.php;
    root  /data/htdocs/www.b.com/;

    #limit_conn   crawler  20;   
                            
    location ~ .*\.(php|php5)?
    {     
      #fastcgi_pass  unix:/tmp/php-cgi.sock;
      fastcgi_pass  127.0.0.1:9001;
      fastcgi_index index.php;
      include fcgi.conf;
    }

}

注意:www.a.com 的请求发送到9000端口 , www.b.com的请求发送到9001端口,依次类推

nginx配置修改了,相对的,php-fpm.conf也要修改

每个站点建一个conf

A站点

#cp /usr/local/webserver/php/etc/php-fpm.conf /usr/local/webserver/php/etc/www.a.com.conf

#vi /usr/local/webserver/php/etc/www.a.com.conf

找到php_defines,添加

<value name="open_basedir">/data/htdocs/www.a.com:/tmp:/var/tmp</value>

 

B站点

#cp /usr/local/webserver/php/etc/php-fpm.conf /usr/local/webserver/php/etc/www.b.com.conf

#vi /usr/local/webserver/php/etc/www.b.com.conf

找到php_defines,添加

<value name="open_basedir">/data/htdocs/www.b.com:/tmp:/var/tmp</value>

 

找到listen_address,修改为

<value name="listen_address">127.0.0.1:9001</value>   注意这里的端口号

 

最后要修改php-fpm启动脚本

#vi /usr/local/webserver/php/sbin/php-fpm

 

注释掉原来的 #php_fpm_BIN –fpm php_opts,田间

php_fpm_BIN –fpm –fpm-config /usr/local/webserver/php/etc/www.a.com.conf

php_fpm_BIN –fpm –fpm-config /usr/local/webserver/php/etc/www.b.com.conf

启动服务

#/usr/local/webserver/php/sbin/php-fpm restart

查看端口

#netstat -tln

 

开了9000 9001分别处理两个站点请求

两个php-cgi主进程加载不同的conf文件,这样就完美解决了虚拟主机webshell能跨目录的问题

当然,启动之前记得conf里面的max_children,开启php-cgi子进程数,相应要减少一些,以免造成内存不足

memcache ajax聊天核心

 

 

PHP代码
  1. function chat_xzy()   
  2.     {   
  3.        if(!$totalnum=cache("chatMsgTotalNum")) $totalnum=cache("chatMsgTotalNum",1,3600*24*50);   
  4.           
  5.         if(isset($_GET[‘ajax’]) && $_GET[‘ajax’]==‘userlist’){   
  6.             $json[‘data’]=getUserOL();   
  7.             $json[‘olusernum’]=olNum();   
  8.             echo json_encode($json);return true;   
  9.         }elseif($_GET[‘ajax’]==‘sendmsg’){   
  10.             $add[‘background’]=strip_tags($_POST[‘background’]);   
  11.             $add[‘color’]=strip_tags($_POST[‘color’]);   
  12.             $add[‘uid’]=$_SESSION[‘user’][‘uid’];   
  13.             $add[‘nickname’]=$_SESSION[‘user’][‘name’];   
  14.             $add[‘touid’]=$_POST[‘touid’];   
  15.             if(!emptyempty($add[‘touid’])){   
  16.                 $a_=db("admin");   
  17.                 $touser=$a_->id($add[‘touid’])->find();   
  18.                 $add[‘tonickname’]=$touser[‘name’];   
  19.             }else{   
  20.                 $add[‘tonickname’]=;   
  21.             }   
  22.             $add[‘msg’]=strip_tags($_POST[‘msg’]);   
  23.             $add[‘time’]=date(‘m-d H:i:s’);   
  24.             $add[‘touid’]=$_POST[‘touid’];   
  25.               
  26.             $totalnum++;   
  27.             cache("chatMsgTotalNum",$totalnum,3600*24*365);   
  28.             cache(‘chatMsgList’.$totalnum,$add,3600*24);   
  29.             $json[‘status’]=0;   
  30.             echo json_encode($json);return true;   
  31.         }elseif($_GET[‘ajax’]==‘showmsg’){   
  32.             if(!$mylastid=cache("chatMsgTotalMy".$_SESSION[‘user’][‘uid’])) $mylastid=cache("chatMsgTotalMy".$_SESSION[‘user’][‘uid’],1,3600*24);   
  33.             $n=$totalnum$mylastid;   
  34.             $list=array();   
  35.             if($n>0){   
  36.                 for($i=1;$i<=$n;$i++){   
  37.                     $x=$mylastid+$i;   
  38.                     $cTmp= cache(‘chatMsgList’.$x);   
  39.                     if(emptyempty($cTmp[‘touid’]) || $cTmp[‘touid’]==$_SESSION[‘user’][‘uid’]) $list[]=$cTmp;   
  40.                 }   
  41.             }   
  42.             cache("chatMsgTotalMy".$_SESSION[‘user’][‘uid’],$totalnum,3600*24);   
  43.             if(!emptyempty($list)){   
  44.                 $json[‘data’]=$list;   
  45.                 $json[‘status’]=0;   
  46.             }else{   
  47.                 $json[‘status’]=1;   
  48.             }   
  49.             echo json_encode($json);return true;   
  50.         }   
  51.         $this->view();   
  52.         $mylastid=cache("chatMsgTotalMy".$_SESSION[‘user’][‘uid’],1,3600*24);   
  53.     }  

 

效果:

 

森.png

REST做api

  REST(Representational State Transfer表述性状态转移)是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。REST提出了一些设计概念和准则:   1.网络上的所有事物都被抽象为资源(resource);   2.每个资源对应一个唯一的资源标识(resource identifier);   3.通过通用的连接器接口(generic connector interface)对资源进行操作;   4.对资源的各种操作不会改变资源标识;   5.所有的操作都是无状态的(stateless)。   对于当今最常见的网络应用来说,resource identifier是url,generic connector interface是HTTP,第4条准则就是我们常说的url不变性。这些概念中的resouce最容易使人产生误解。resouce所指的并不是数 据,而是数据+特定的表现形式(representation),这也是为什么REST的全名是Representational State Transfer的原因。举个例子来说,“本月卖得最好的10本书”和“你最喜欢的10本书”在数据上可能有重叠(有一本书即卖得好,你又喜欢),甚至完 全相同。但是它们的representation不同,因此是不同的resource。   REST之所以能够简化开发,是因为其引入的架构约束,比如Rails 1.2中对REST的实现默认把controller中的方法限制在7个:index、show、new、edit、create、update和 destory,这实际上就是对CURD的实现。更进一步讲,Rails(也是当今大部分网络应用)使用HTTP作为generic connector interface,HTTP则把对一个url的操作限制在了4个之内:GET、POST、PUT和DELETE。   REST之所以能够提高系统的可伸缩性,是因为它强制所有操作都是stateless的,这样 就没有context的约束,如果要做分布式、做集群,就不需要考虑context的问题了。同时,它令系统可以有效地使用pool。REST对性能的另 一个提升来自其对client和server任务的分配:server只负责提供resource以及操作resource的服务,而client要根据 resource中的data和representation自己做render。这就减少了服务器的开销。   既然REST有这样的好处,那我们应该义无反顾地拥抱它啊!目前一些大牛(像DHH)都已经开 始投入到了REST的世界,那我们这些人应该做什么或者说思考写什么你呢?我觉得我们应该思考两个问题:   如何使用REST;   REST和MVC的关系。   第一个问题假设REST是我们应该采用的架构,然后讨论如何使用;第二个问题则要说明REST 和当前最普遍应用的MVC是什么关系,互补还是取代?   我们先来谈谈第一个问题,如何使用REST。我感觉,REST除了给我们带来了一个崭新的架构 以外,还有一个重要的贡献是在开发系统过程中的一种新的思维方式:通过url来设计系统的结构。根据REST,每个url都代表一个resource,而 整个系统就是由这些resource组成的。因此,如果url是设计良好的,那么系统的结构就也应该是设计良好的。对于非高手级的开发人员来说,考虑一个 系统如何架构总是一个很抽象的问题。敏捷开发所提倡的Test Driven Development,其好处之一(我觉得是最大的好处)就是可以通过testcase直观地设计系统的接口。比如在还没有创建一个class的时候就 编写一个testcase,虽然设置不能通过编译,但是testcase中的方法调用可以很好地从class使用者的角度反映出需要的接口,从而为 class的设计提供了直观的表现。这与在REST架构中通过url设计系统结构非常类似。虽然我们连一个功能都没有实现,但是我们可以先设计出我们认为 合理的url,这些url甚至不能连接到任何page或action,但是它们直观地告诉我们:系统对用户的访问接口就应该是这样。根据这些url,我们 可以很方便地设计系统的结构。   让我在这里重申一遍:REST允许我们通过url设计系统,就像Test Driven Development允许我们使用testcase设计class接口一样。   OK,既然url有这样的好处,那我们就着重讨论一下如何设计url。网络应用通常都是有 hierarchy的,像棵大树。我们通常希望url也能反映出资源的层次性。比如对于一个blog应用:/articles表示所有的文章, /articles/1表示id为1的文章,这都比较直观。遗憾的是,网络应用的资源结构永远不会如此简单。因此人们常常会问这样一个问 题:RESTful的url能覆盖所有的用户请求吗?比如,login如何RESTful?search如何RESTful?   从REST的概念上来看,所有可以被抽象为资源的东东都可以使用RESTful的url。因此 对于上面的两个问题,如果login和search可以被抽象为资源,那么就可以使用RESTful的url。search比较简单,因为它会返回搜索结 果,因此可以被抽象为资源,并且只实现index方法就可以了(只需要显示搜索结果,没有create、destory之类的东西)。然而这里面也有一个 问题:search的关键字如何传给server?index方法显然应该使用HTTP GET,这会把关键字加到url后面,当然不符合REST的风格。要解决这个问题,可以把每次search看作一个资源,因此要创建create和 index方法,create用来在用户点击“搜索”按钮是通过HTTP POST把关键字传给server,然后index则用来显示搜索结果。这样一来,我们还可以记录用户的搜索历史。使用同样的方法,我们也可以对 login应用REST,即每次login动作是一个资源。   现在,我们来看复杂一些的东东。如何用url表达“category为ruby的 article”?一开始可能想到的是/category/ruby/articles,这种想法很直观。但是我觉得里面的category是不需要的, 我们可以直接把“/ruby”理解为“category是ruby”,也就是说“ruby”出现的位置说明了它指的就是category。OK, /ruby/articles,单单从这个url上看,我们能获得多少关于category的信息呢?显然category隐藏在了url后面,这样做到 底好不好,应该是仁者见仁,智者见智了。对于如何表达category这样的东西,我还没想出很好的方式,大家有什么好idea,可以一起讨论。   另外还有一种url形式,它对应到程序中的继承关系。比如product是一个父类,book 和computer是其子类。那么所有产品的url应该是/products,所有书籍的url应该是/books,所有电脑的url应该是 /computers。这一想法就比较直观了,而且再次验证了url可以帮助我们进行设计的论点。   让我再说明一下我的想法:如果每个用户需求都可以抽象为资源,那么就可以完全使用REST。   由此看来,使用REST的关键是如何抽象资源,抽象得越精确,对REST的应用就越好。因此, 如何改变我们目前根深蒂固的基于action的思想是最重要的。   有了对第一个问题的讨论,第二个问题就容易讨论多了。REST会取代MVC吗?还是彼此是互补 关系(就像AOP对于OOP)?答案是It depends!如果我们可以把所有的用户需求都可以抽象为资源,那么MVC就可以退出历史的舞台了。如果情况相反,那么我们就需要混合使用REST和 MVC。   当然,这是非常理想的论断。可能我们无法找到一种方法可以把所有的用户需求都抽象为资源,因为 保证这种抽象的完整性(即真的是所有需求都可以)需要形式化的证明。而且即使被证明出来了,由于开发人员的能力和喜好不同,MVC肯定也会成为不少人的首 选。但是对于希望拥抱REST的人来说,这些都没有关系。只要你开发的系统所设计的问题域可以被合理地抽象为资源,那么REST就会成为你的开发利器。

自己写的一个php mvc框架,加示例26k

自己写的一个框架,用它做过一些项目,开发效率上还可以。小型框架,主要的部分:

mysql原生或是pdo支持、 缓存处理、 支持memcache 、支持session入库 、session入memcache 、 4种链接方式可选  、生成html、rbac管理、分页处理

提供下载,放出来让php高手们看看,有bug或是不合理的地方,还请大家能指出,谢谢了!

另外:本框架是自己使用,不做为框架产品供大家使用,如果使用后产生的一切类似安全方面的后果自负,同时也不会做版本的更新!

xzyframework.zip

用c++把自动新建、修改虚拟主机的shell重写了一下

 

以后想自己写个ubuntu下的虚拟主机管理系统,嘿嘿!目前已搞定了apache新建用户、删除用户、vsftp mysql管理。

C++代码
  1. #include <iostream>   
  2. #include <fstream>   
  3. #include <string>   
  4. #include<stdlib.h>   
  5.   
  6. using namespace std;   
  7. string stringReplace(const string& input,const string& find,const string& replaceWith)   
  8.   
  9. {   
  10.     string   strOut(input);   
  11.     int   curPos   =   0;   
  12.     int   pos;   
  13.     while((pos   =   strOut.find(find,   curPos))   !=   -1)   
  14.     {   
  15.         strOut.replace(pos,   find.size(),   replaceWith);   
  16.         curPos   =   pos   +   replaceWith.size();   
  17.     }   
  18.     return   strOut;   
  19. }   
  20.   
  21.   
  22.   
  23. int main(int argc,char *argv[])   
  24. {   
  25.         int i=3;   
  26.         cout<<argv[1]<<"|"<<argv[2]<<endl;   
  27.         if(argv[1]=="diyweb"){   
  28.                 cout<<"error,diyweb is system user"<<endl;   
  29.                 return 0;   
  30.         }   
  31.         if(argv[1]=="000-default"){   
  32.                 cout<<"error,000-default is system user"<<endl;   
  33.                 return 0;   
  34.         }   
  35.         //cin.get();   
  36.         string filename="/etc/apache2/sites-enabled/"+string(argv[1]);   
  37.   
  38.         ofstream f1(filename.c_str());   
  39.   
  40.         if(!f1){   
  41.                 cout<<"error,file not open!"<<endl;   
  42.                 return 0;   
  43.         }   
  44.         string doname=stringReplace(string(argv[2]),"@"," ");   
  45.         string content="<VirtualHost *:80>\nServerName "+string(argv[1])+".ye55.net \nServerAlias "+string(argv[1])+".armos.cn "+doname+" \nDocumentRoot \"/home/web/diyweb/company/"+string(argv[1])+"\"\n</VirtualHost>";   
  46.         f1<<content<<endl;   
  47.         f1.close();   
  48.         system("sudo /etc/init.d/apache2 reload >tmp.out");   
  49.         cout<<"success"<<endl;   
  50.         return 0;   
  51.   
  52. }   

发一个自动新建、修改虚拟主机的shell脚本

 今天重新弄了下自助建站的虚拟主机管理程序,服务器ubuntu 10.04 server 64位,安装apache+php+mysql

写了个脚本,给php调用,在新建用户账号、修改或绑定域名时起执行的,运用了apache 的reload,添加虚拟主机免重启方案!

然后就是用visudo给apache的用户www-data授权,允许用root身份执行这个脚本及/etc/init.d/apache2 二条命令。

这样web就可以执行新建及修改虚拟主机的操作了,但是目前还是不太安全的,www-data有关闭和启动apache的权限,下次找个时间,重新写个apache2的reload专用脚本。不使用/etc/init.d/apache2脚本。!

Ruby代码
  1. #!/bin/sh   
  2. FILENAME=/etc/apache2/sites-enabled/$1  
  3. if [ $1 = "diyweb" ] ; then  
  4.         echo ‘error ,diyweb is system user!’;   
  5. elif [ $1 = ‘000-default’ ] ; then  
  6.         echo ‘error ,000-default is sysytem user’;   
  7. else  
  8. if [ -f $FILENAME ]; then  
  9.         echo ‘Del old file’;   
  10.         rm -rf $FILENAME  
  11.         echo ‘Update user’  
  12. else  
  13.         echo ‘Add user’  
  14. fi   
  15.         echo "<VirtualHost *:80>\nServerName $1.ye55.net \nServerAlias $1.armos.cn $2 \nDocumentRoot \"/home/web/diyweb/company/$1\"\n</VirtualHost>" >> $FILENAME  
  16.         sed ‘s/@/ /g’ $FILENAME -i   
  17.         echo ‘Success’  
  18.         /etc/init.d/apache2 reload   
  19. fi  

写的一个vpn自动重连脚本

XML/HTML代码
  1. #!/bin/sh   
  2. VPN=`ifconfig | grep ppp0`   
  3. #echo $VPN   
  4. if [ -z "$VPN" ]   
  5. then   
  6. pon myvpn   
  7. route add -net 10.10.10.0 netmask 255.255.255.0 dev ppp0   
  8. else   
  9. echo $VPN >/dev/null   
  10. fi  

 

公司内部的服务器连接到外网的vpn ,从而方便进行远程内部访问及操作。内部服务器系统是ubuntu 10.04 server 64位版,外网服务器windows 2003 做vpn服务。linux 中的pptp-linux登陆后需要执行route添加路由才能访问vpn内网。

脚本的意思是监控ppp0连接是否正常,如果没有ppp0接连则自动开启vpn拨号,并把日志写入root邮件 /var/mail/root

脚本编写后放入crontab -e   

* * * * * root /root/vpn.sh