示范sed指定某行插入 追加和全局替换

有时候会有这样的需求,在指定的行后面或者是前面追加一行,这个时候可以使用sed来完成,具体用法如下

  • a 在指定的行后面追加一行

  • b 在指定的行前面追加一行

使用指定的行号追加内容,在使用行号的过程中,需要注意的问题有以下

  • N;后面只能使用偶数,且不可以为0

  • a表示在指定的行后面追加一行

  • i表示在当前行插入一行,如果指定行为4,其实最终的结果插入行的位置是第三行。

sed -i 'N;2anewline' 1.txt

sed -i 'N;2inewline' 1.txt
[root@lanmp shell]# cat << eof > 1.txt

> a

> b

> c

> d

> eof

[root@lanmp shell]# sed -i 'N;2a2222' 1.txt

[root@lanmp shell]# cat 1.txt

a

b

2222

c

d

[root@lanmp shell]# sed -i 'N;2i2222' 1.txt

[root@lanmp shell]# cat 1.txt

2222

a

b

2222

c

d
[root@RS2 shell]# cat 1.txt

1111

3333

[root@RS2 shell]# sed -i '/^1111$/a2222' 1.txt ; cat 1.txt

1111

2222

3333

[root@RS2 shell]# sed -i '/^1111$/i000' 1.txt ; cat 1.txt

0000

1111

2222

3333

下面是把所有匹配的字符都替换为指定的字符

[root@SLAVE ~]# cat << eof > 1.txt

> 1111

> 222333333

> 44444444445

> eof

[root@SLAVE ~]# sed -i 2{s/2/3/g} 1.txt

[root@SLAVE ~]# cat 1.txt

1111

333333333

44444444445

[root@SLAVE ~]# sed -i 3{s/4/5/g} 1.txt

[root@SLAVE ~]# cat !$

cat 1.txt

1111

333333333

55555555555

saltstack自动安装配置redis-3.2.8

一、准备redis自动化配置的文件

即安装一遍redis,然后获取相关文件和配置在salt中执行上线

1、 源码安装redis3.2.8并注册为系统服务

安装依赖

yum install -y tcl

1.1 下载安装包Redis-3.2.8.tar.gz

# cd /usr/local/src
# wget http://download.redis.io/releases/redis-3.2.8.tar.gz

1.2 解压及安装

[root@node2 src]# tar zxf redis-3.2.8.tar.gz
[root@node2 src]# cd redis-3.2.8/src/
[root@node2 redis-3.2.8]# make PREFIX=/usr/local/redis install #指定安装路径

1.3 创建配置文档,修改配置

创建配置文档路径

# mkdir /etc/redis
[root@node2 src]# cp ../redis.conf /etc/redis/redis_6350.conf

以下几个参数常用到

daemonize yes # 后台运行
bind 127.0.0.1 # 绑定ip,需要外网访问时将其注释掉
protected-mode yes # 保护模式,默认是开启的,需要其他客户端链接时,改为no关闭
requirepass redispass # 其他客户端链接时的密码
appendonly yes # 每次更新后记录日志
pidfile /var/run/redis_6350.pid # 如果不是默认的6379端口需要修改该行

1.4 注册系统服务,开机自启

创建启动脚本

# cp ../utils/redis_init_script /etc/rc.d/init.d/redis3

修改redis启动脚本,要修改的地方有

添加 chkconfig 注释

redis-server 、redis-cli 、pidfile、redis.conf路径

如果需要配置密码,还要在停止命令增加参数 -a 指定密码

[root@node2 src]# cat /etc/init.d/redis3 

#!/bin/sh
# chkconfig:   2345 90 10
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.

REDISPORT=6350
EXEC=/usr/local/redis/bin/redis-server
CLIEXEC=/usr/local/redis/bin/redis-cli

PIDFILE=/var/run/redis_${REDISPORT}.pid
CONF="/etc/redis/redis_${REDISPORT}.conf"

usage(){
    echo "usage: $0 [start|stop|status|restart]"
}

redis_start(){
if [ -f $PIDFILE ]
    then
            echo "$PIDFILE exists, process is already running or crashed"
    else
            echo "Starting Redis server..."
            $EXEC $CONF
fi
}

redis_stop(){
    if [ ! -f $PIDFILE ]
    then
            echo "$PIDFILE does not exist, process is not running"
    else
            PID=$(cat $PIDFILE)
            echo "Stopping ..."
            $CLIEXEC -p $REDISPORT -a redispass shutdown
            while [ -x /proc/${PID} ]
            do
                echo "Waiting for Redis to shutdown ..."
                sleep 1
            done
            echo "Redis stopped"
    fi
}

redis_restart(){
    redis_stop
    sleep 1
    redis_start
}
redis_status(){
    ps -ef|grep redis|grep -v grep|grep -v status
}

main(){
    case "$1" in
        start)
            redis_start;;
        stop)
            redis_stop;;
        status)
            redis_status;; 
        restart)
            redis_restart;;
        *)
            usage;
    esac
}

main $1

保存后执行注册成系统服务:

chkconfig --add redis3
chkconfig redis3 on

完成后,可以使用 service redis3 start|stop 启动关闭redis服务

1.5 添加环境变量:

vim /etc/profile

在最后添加:

PATH=$PATH:/usr/local/redis/bin
export PATH

# 使配置生效
source /etc/profile

# service redis3 start
[root@node2 src]# ps -ef|grep redis
root     20818     1  0 09:57 ?        00:00:00 /usr/local/redis/bin/redis-server 127.0.0.1:6350
root     20827 14125  0 09:58 pts/0    00:00:00 grep --color=auto redis

用redis-cli 链接,set,get正常

[root@node2 src]# redis-cli -p 6350 -a redispass

127.0.0.1:6350> set name 2
OK
127.0.0.1:6350> get name
"2"
127.0.0.1:6350> set jack 18
OK
127.0.0.1:6350> get jack
"18"
127.0.0.1:6350> quit

二、salt相关的配置处理

# mkdir -p /srv/salt/prod/pkg /srv/salt/prod/redis /srv/salt/prod/redis/files 
# cd /srv/salt/prod/pkg

1、 初始化nginx相关配置文件

①下载redis-3.2.8.tar.gz上传到/srv/salt/prod/redis/files目录

②配置文件

[root@test7_chat_api_im files]# grep '^[a-Z]' redis_6350.conf 
bind 127.0.0.1
protected-mode yes
port 6350
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
supervised no
pidfile /var/run/redis_6350.pid
loglevel notice
logfile ""
databases 16
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir ./
slave-serve-stale-data yes
slave-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
slave-priority 100
requirepass redispass
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes

③服务管理脚本

[root@test7_chat_api_im files]# cat redis3 
#!/bin/sh
# chkconfig:   2345 90 10
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.

REDISPORT=6350
EXEC=/usr/local/redis/bin/redis-server
CLIEXEC=/usr/local/redis/bin/redis-cli

PIDFILE=/var/run/redis_${REDISPORT}.pid
CONF="/etc/redis/redis_${REDISPORT}.conf"

case "$1" in
    start)
        if [ -f $PIDFILE ]
        then
                echo "$PIDFILE exists, process is already running or crashed"
        else
                echo "Starting Redis server..."
                $EXEC $CONF
        fi
        ;;
    stop)
        if [ ! -f $PIDFILE ]
        then
                echo "$PIDFILE does not exist, process is not running"
        else
                PID=$(cat $PIDFILE)
                echo "Stopping ..."
                $CLIEXEC -p $REDISPORT -a redispass shutdown
                while [ -x /proc/${PID} ]
                do
                    echo "Waiting for Redis to shutdown ..."
                    sleep 1
                done
                echo "Redis stopped"
        fi
        ;;
    *)
        echo "Please use start or stop as first argument"
        ;;
esac

2、 编写依赖包安装

vim /srv/salt/prod/pkg/pkg-init.sls

pkg-init:
  pkg.installed:
    - names:
      - gcc
      - gcc-c++
      - glibc
      - make
      - autoconf
      - openssl
      - openssl-devel
      - pcre
      - pcre-devel
      - glib
      - glib-devel
      - tcl

3、 用户添加模块

# mkdir /srv/salt/prod/user
# vim /srv/salt/prod/user/redis.sls 
redis-user-group:
  group.present:
    - name: redis
    - gid: 6350

  user.present:
    - name: redis
    - fullname: redis
    - shell: /sbin/nologin
    - uid: 6350
    - gid: 6350

4、 编写nginx状态模块

# cd /srv/salt/prod/redis
vim /srv/salt/prod/redis/install.sls

include:
  - pkg.pkg-init
  - user.redis
redis-source-install:
  file.managed:
    - name: /usr/local/src/redis-3.2.8.tar.gz
    - source: salt://redis/files/redis-3.2.8.tar.gz
    - user: root
    - group: root
    - mode: 755
  cmd.run:
    - name: cd /usr/local/src && tar zxf redis-3.2.8.tar.gz && cd cd redis-3.2.8/src/ && make PREFIX=/usr/local/redis install && chown -R redis:redis /usr/local/redis && mkdir /etc/redis
    - unless: test -d /usr/local/redis
    - require:
      - user: redis-user-group
      - file: redis-source-install
      - pkg: pkg-init

服务模块

# vim /srv/salt/prod/redis/service.sls 
include:
  - redis.install

redis-init:
  file.managed:
    - name: /etc/init.d/redis3
    - source: salt://redis/files/redis3
    - mode: 755
    - user: root
    - group: root
    - require:
      - cmd: redis-source-install
  cmd.run:
    - name: chkconfig --add redis3
    - unless: chkconfig --list | grep redis
    - require:
      - file: redis-init

/etc/redis/redis_6350.conf:
  cmd.run:
    - name: mkdir /etc/redis
  file.managed:
    - source: salt://redis/files/redis_6350.conf
    - user: redis
    - group: redis
    - mode: 644 

redis-service:
  service.running:
    - name: redis3
    - enable: True
    - restart: True
    - require:
      - cmd: redis-init
    - watch:
      - file: /etc/redis/redis_6350.conf

执行配置测试,没有问题再安装,至此salt安装redis服务已完毕:

# 先测试先处理一些简单的错误

salt 'test4_haili_dev' state.sls redis.service env=prod test=True

salt 'test4_haili_dev' state.sls redis.service env=prod

Ubuntu系统配置rsync文件同步服务

简介

rsync(remote synchronize)是类unix系统下的实现远程数据同步功能的工具,它的特性如下:

  • 可以镜像保存整个目录树和文件系统
  • 可以很容易做到保持原来文件的权限、事件、软硬链接等信息
  • 无需特殊权限即可安装
  • 快速:第一次同步时 rsync 会复制全部内容,但在下一次只传输修改过的文件。rsync 在传输数据的过程中可以实行压缩及解压缩操作,因此可以使用更少的带宽。
  • 安全:可以使用scp、ssh等方式来传输文件,当然也可以通过直接的socket连接。
  • 支持匿名传输,以方便进行网站镜象。

安装

在Ubuntu下安装rsync通过以步骤可以实现:

sudo apt-get install rsync xinetd

默认情况下Ubuntu安装了rsync,因此只需安装xinetd

服务器端配置

1、 编辑/etc/default/rsync 启动rsync作为使用xinetd的守护进程

# 打开rsync
sudo vim /etc/default/rsync
# 编辑rsync
RSYNC_ENABLE=inetd

2、 创建/etc/xinetd.d/rsync, 通过xinetd使rsync开始工作

# 创建并打开文件
sudo vim /etc/xinetd.d/rsync
# 编辑内容
service rsync
{
    disable         = no
    socket_type     = stream
    wait            = no
    user            = root
    server          = /usr/bin/rsync
    server_args     = --daemon
    log_on_failure  += USERID
}

3、 创建/etc/rsyncd.conf,并填写配置信息

# 创建并打开文件
sudo vim /etc/rsyncd.conf
# 编辑配置信息
max connections = 2
log file = /var/log/rsync.log
timeout = 300

[share] # 模块名
comment = Public Share
# path为需要同步的文件夹路径
path = /home/share
read only = no
list = yes
uid = root
gid = root
# 必须和 rsyncd.secrets中的用户名对应
auth users = user
secrets file = /etc/rsyncd.secrets

4、 创建/etc/rsyncd.secrets,配置用户名和密码.

# 创建并打开文件
sudo vim /etc/rsyncd.secrets
# 配置用户名和密码,密码可以任意设置
user:password

5、 修改rsyncd.secrets文件的权限

sudo chmod 600 /etc/rsyncd.secrets

6、 启动/重启 xinetd

sudo /etc/init.d/xinetd restart

客户端配置

由于我用的系统是windows,所以需要在windows上安装rsync的客户端cwRsync

1、 下载并安装cwRsync

下载地址http://pan.baidu.com/s/1pJ3B1FX

2、 安装后将其添加到环境变量path中,我的cwRsync安装在D:cwRsync目录下,将D:cwRsyncbin添加到环境变量path中

测试

在客户端运行下面的命令检查,确认rsync配置成功

# user是在服务器中rsyncd.secrets文件中配置的用户名
# xx.xx.xx.xx 是服务器的ip地址,也可以填写服务器对应的域名
# share 是rsyncd.conf中定义的模块
rsync [email protected]::share

输入密码后,如果输出以下类似内容,说明配置成功

drwxr-xr-x        4096 2006/12/13 09:41:59 .
drwxr-xr-x        4096 2006/11/23 18:00:03 folders

同步

1、 将本地文件同步至服务器

将当前目录下public路径下的全部内容,同步至服务器,服务器的同步路径在rsyncd.conf中指定

rsync -av ./public/ [email protected]::share

2、 将服务器文件同步至本地

rsync -cvazu --progress [email protected]::share /rsyn

使用inotify rsync实现linux文件批量实时更新

如果只对经常改动的目录进行同步,也可以忽略这个问题,如果每次改动的目录多较大,那么就要用到inotify了,Inotify是一种强大的、细粒度的、异步的文件系统事件监控机制,Linux内核从2.6.13起,加入了对Inotify的支持,通过Inotify可以监控文件系统中的添加、删除、修改、移动等各种事件,但inotify只提供了C语言接口,不方便调用,所以我们需要先安装inotify-tools

系统环境

CentOS_5.7-x86_64
更新源服务器:192.168.9.227
目的服务器:192.168.9.226 192.168.9.228 …

目的服务器配置

192.168.9.226 192.168.9.228(rsync服务端):

检查rsync是否安装

rpm -qa|grep rsync

如果没有发装,执以下命令进行安装

yum -y install rsync

定义rsync配置文件/etc/rsyncd.conf

192.168.9.226:

cat >> /etc/rsyncd.conf << EOF
uid = nobody 
gid = nobody 
use chroot = no 
max connections = 100 
timeout = 600 
pid file = /var/run/rsyncd.pid 
lock file = /var/run/rsyncd.lock 
log file = /var/log/rsyncd.log 
[web1] 
path = /data/www1/ 
ignore errors 
read only = no 
list = no 
hosts allow = 192.168.9.0/255.255.255.0 
auth users = www1 
secrets file = /etc/www1.pwd 
EOF

192.168.9.228:

cat >> /etc/rsyncd.conf << EOF
uid = nobody 
gid = nobody 
use chroot = no 
max connections = 100 
timeout = 600 
pid file = /var/run/rsyncd.pid 
lock file = /var/run/rsyncd.lock 
log file = /var/log/rsyncd.log 
[web2] 
path = /data/www2/ 
ignore errors 
read only = no 
list = no 
hosts allow = 192.168.9.0/255.255.255.0 
auth users = www2 
secrets file = /etc/www2.pwd 
EOF

rsyncd.conf配置文件详解

uid = nobody //运行RSYNC守护进程的用户
gid = nobody //运行RSYNC守护进程的组
use chroot = 0 //不使用chroot
max connections = 0 // 最大连接数,0为不限制
port = 873 //默认端口873
下面这些文件是安装完RSYNC服务后自动生成的文件
pid file = /var/run/rsyncd.pid //pid文件的存放位置
lock file = /var/run/rsync.lock //锁文件的存放位置.指定支持max connections参数的锁文件,默认值是/var/run/rsyncd.lock.
log file = /var/log/rsyncd.log //日志记录文件的存放位置
Timeout = 300 通过该选项可以覆盖客户指定的IP超时时间.通过该选项可以确保rsync服务器不会永远等待一个崩溃的客户端.超时单位为秒钟,0表示没有超时定义,这也是默认值.对于匿名rsync服务器来说,一个理想的数字是600.
Log format = %t %a %m %f %b 通过该选项用户在使用transfer logging可以自己定制日志文件的字段.其格式是一个包含格式定义符的字符串,可以使用的格式定义符如下所示:
%h 远程主机名
%a 远程IP地址
%l 文件长度字符数
%p 该次rsync会话的进程id
%o 操作类型:" send" 或" recv"
%f 文件名
%P 模块路径
%m 模块名
%t 当前时间
%u 认证的用户名(匿名时是null)
%b 实际传输的字节数
%c 当发送文件时,该字段记录该文件的校验码
默认log格式为:" %o %h [%a] %m (%u) %f %l" ,一般来说,在每行的头上会添加" %t [%p] " .在源代码中同时发布有一个叫rsyncstats的perl脚本程序来统计这种格式的日志文件.
#transfer logging = yes
使rsync服务器使用ftp格式的文件来记录下载和上载操作在自己单独的日志中.
syslog facility = local3 指定rsync发送日志消息给syslog时的消息级别,常见的消息级别是:uth, authpriv, cron, daemon, ftp, kern, lpr, mail, news, security, sys-log, user, uucp, local0, local1, local2, local3,local4, local5, local6和local7.默认值是daemon.
模块参数 [web1] //这里是认证的模块名,在client端需要指定
path = /data/www1/ //需要做镜像的目录,不可缺少!
comment = backup web //这个模块的注释信息
ignore errors //可以忽略一些无关的IO错误
read only = yes //该选项设定是否允许客户上载文件.如果为true那么任何上载请求都会失败,如果为false并且服务器目录读写权限允许那么上载是允许的.默认值为true.
list = no //不允许列文件
auth users = bak //认证的用户名,如果没有这行则表明是匿名,此用户与系统无关 该选项指定由空格或逗号分隔的用户名列表,只有这些用户才允许连接该模块.这里的用户和系统用户没有任何关系.如果" auth users" 被设置,那么客户端发出对该模块的连接请求以后会被rsync请求challenged进行验证身份这里使用的challenge/response认证协议.用户的名和密码以明文方式存放在" secrets file" 选项指定的文件中.默认情况下无需密码就可以连接模块(也就是匿名方式).
secrets file = /etc/www1.pwd //密码和用户名对比表,密码文件自己生成 该选项指定一个包含定义用户名:密码对的文件.只有在" auth users" 被定义时,该文件才有作用.文件每行包含一个username:passwd对.一般来说密码最好不要超过8个字符.没有默认的secures file名,需要限式指定一个(例如:/etc/www1.pwd).注意:该文件的权限一定要是600,否则客户端将不能连接服务器.
hosts allow = 192.168.9.0/255.255.255.0 //允许主机或网段
该选项指定哪些IP的客户允许连接该模块.客户模式定义可以是以下形式:
单个IP地址,例如:192.168.9.227
整个网段,例如:192.168.9.0/24,也可以是192.168.9.0/255.255.255.0
多个IP或网段需要用空格隔开,“*”则表示所有,默认是允许所有主机连接.
hosts deny = 0.0.0.0/0 //禁止主机

建立认证文件/etc/www1.pwd

此文件须与配置文件中指定文件名保持一致
此处格式为:username:password,安全问题,并不建议实际使用中使用root用户
192.168.9.226:

echo "www1:741852" >> /etc/www1.pwd

192.168.9.228:

echo "www2:951753" >> /etc/www2.pwd

并且我们需要设置此文件的权限为600

chmod 600 /etc/www1.pwd
chmod 600 /etc/www2.pwd
chmod 600 /etc/rsyncd.conf

建立motd文件(可有可无)

rsyncd.motd记录了rsync服务的欢迎信息,你可以在其中输入任何文本信息,如:

echo "Welcome to use the rsync services!" >> /var/rsyncd.motd

启动rsync

/usr/bin/rsync --daemon
echo "/usr/bin/rsync --daemon" >> /etc/rc.local

更新源服务器配置

192.168.9.227 (rsync客户端)

inotify 可以监视的文件系统事件包括

IN_ACCESS,即文件被访问
IN_MODIFY,文件被 write
IN_ATTRIB,文件属性被修改,如 chmod、chown、touch 等
IN_CLOSE_WRITE,可写文件被 close
IN_CLOSE_NOWRITE,不可写文件被 close
IN_OPEN,文件被 open
IN_MOVED_FROM,文件被移走,如 mv
IN_MOVED_TO,文件被移来,如 mv、cp
IN_CREATE,创建新文件
IN_DELETE,文件被删除,如 rm
IN_DELETE_SELF,自删除,即一个可执行文件在执行时删除自己
IN_MOVE_SELF,自移动,即一个可执行文件在执行时移动自己
IN_UNMOUNT,宿主文件系统被 umount
IN_CLOSE,文件被关闭,等同于(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
IN_MOVE,文件被移动,等同于(IN_MOVED_FROM | IN_MOVED_TO)

注:上面所说的文件也包括目录。

安装inotify-tools

在安装inotify-tools前请先确认你的linux内核是否打到了2.6.13,并且在编译时开启了CONFIG_INOTIFY选项,也可以通过以下命令检测

ls /proc/sys/fs/inotify

如果有 max_queued_events,max_user_instances,max_user_watches 三项就说明支持

wget http://cloud.github.com/downloads/rvoicilas/inotify-tools/inotify-tools-3.14.tar.gz
tar xvf inotify-tools-3.14.tar.gz
cd inotify-tools-3.14
./configure
make;make install

编写rsync监控脚本

vi /root/rsync.sh
#!/bin/bash
host1=192.168.9.226
host2=192.168.9.228
src=/data/www/
des1=web1
des2=web2
user1=www1
user2=www2
/usr/local/bin/inotifywait -mrq --timefmt '%d/%m/%y %H:%M' --format '%T %w%f' 
-e modify,delete,create,attrib 
${src} 
| while read file
do
rsync -vzrtopg --delete --progress ${src} ${user1}@${host1}::${des1} --password-file=/etc/www1.pwd &&
rsync -vzrtopg --delete --progress ${src} ${user2}@${host2}::${des2} --password-file=/etc/www2.pwd &&
echo "${files} was rsynced" >> /tmp/rsync.log 2>&1
echo "---------------------------------------------------------------------------"
done
-m, 即--monitor,表示始终保持事件监听状态。
-r, 即--recursive,表示递归查询目录。
-q, 即--quiet,表示打印出监控事件。
-e, 即--event,通过此参数可以指定要监控的事件,常见的事件有modify、delete、create、attrib等
--timefmt:指定时间的输出格式
--format:指定变化文件的详细信息

建立认证文件 (rsync客户端认证文件只用加入密码)

echo "741852" >> /etc/www1.pwd
echo "951753" >> /etc/www2.pwd
chmod 600 /etc/www1.pwd
chmod 600 /etc/www2.pwd
/bin/sh -n /root/rsync.sh //语法检查
chmod +x /root/rsync.sh
nohup sh /root/rsync.sh &
echo "nohup sh /root/rsync.sh &" >> /etc/rc.local

同步测试

在更新源服务器上新建一个文件,运行以下的命令,看文件是否可以正常同步,看有无报错信息

rsync -vzrtopg --delete --progress /data/www1/ [email protected]::web1 --password-file=/etc/www1.pwd

将要更新的文件提交到更新源服务器中,这样就通过inotify+rsync批量的将更新文件同步到所有的目的服务器中,相当方便快捷.

Python3.5多线程爬虫越爬越慢的解决方法

系统环境

Ubuntu 16.04 Server
Python3.5

爬虫情况

1、从Mysql数据库获取任务
2、任务导入列表后开始http请求,将数据以文件形式保存到硬盘
3、开80线程

遇到的问题

1、家用路由器频繁死机(一天两三次)
2、爬虫开始时爬取速度很快,但是越来越慢

解决思路

查看爬虫日志发现路由器死机前,爬虫速度基本都在峰值,看来是路由器是累晕的,爬虫开始时速度快然后越来越慢,说明爬虫本身问题不大,应该是运行后消耗的系统资源越来越多,直到消耗殆尽而导致速度上不去。查看内存和cpu的消耗情况发现,在爬虫速度降低之后内存cpu的占用也有降低,看来问题不在硬件资源,那是不是网络资源内,使用netstat命令查看发现有大量“TIME_WAIT”状态的TCP连接,使用命令

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

查看发现TIME_WAIT状态的连接近2w,看来是资源tcp连接过多!此时想是不是爬虫http头部信息中Connection的问题呢,把Keep-Alive改为close并未解决问题!那Ubuntu有没有设置tcp连接控制方面的选项呢?通过搜索得知,tcp连接可以设置回收时间和是否可以复用,命令如下:

echo "1" > /proc/sys/net/ipv4/tcp_tw_reuse
#设置TIME_WAIT状态可以重用
echo "1" > /proc/sys/net/ipv4/tcp_tw_recycle
#设置TCP连接尽快回收

使用以上命令后问题果然解决!

CentOS 6.5升级Python版本 修复yum和安装模块

CentOS python版本是V2.6.6,升级3.4.3。

  • 下载 安装包
wget http://www.python.org/ftp/python/3.4.3/Python-3.4.3.tgz
  • 解压安装包
tar -zxvf Python-3.4.3.tgz  
  • 进入解压后目录
cd Python-3.4.3   
  • 编译安装
./configure --prefix=/usr/local/python3.3
make && make install
  • 此时已完成新版本的安装,但由于老版本还在系统中,所以需要将原来/usr
    /bin/python链接改为新的连接

a.先修改老的连接,执行

mv /usr/bin/python /usr/bin/python2.6

b.再建立新连接

ln -s /usr/local/python3.3/bin/python3.3 /usr/bin/python
  • 查询python版本
python

解决升级后YUM无法使用

  • 打开/usr/bin/yum
vim /usr/bin/yum

将#!/usr/bin/python 修改为 #!/usr/bin/python2.6,保存退出

  • 测试是否修复
yum list  

使用easy_install和 pip 安装模块

  • 一些依赖
yum install mysql-devel zlib-devel gcc python-devel gcc libffi-devel python-devel openssl-devel readline-devel patch
  • A: yum 安装 easy_install
yum install python-setuptools
  • B: 通过ezsetup.py安装easyinstall
wget --no-check-certificate https://bootstrap.pypa.io/ez_setup.py
python ez_setup.py --insecure
  • 举个例子:安装模块paramiko,以下两种方法都可以
easy_install paramiko
pip install paramiko
  • 安装带setup.py的多文件模块包,下载后,解压,进入目录
python setup.py install

php-fpm占用内存过高分析及解决

昨天刚买了个vps搭建了一个wordPress博客,刚搭建的时候有一大堆的问题。好不容易搭建完成了发现运行一阵子以后内存几乎用完了。开始以为是服务器的问题,费了好大的劲把Apache服务器换成了Nginx。但是问题还是没有解决,最后用top命令看了一下是php-fpm的问题。问题的解决办法如下:

未分类

1、查看php-fpm的进程个数

ps -fe |grep "php-fpm"|grep "pool"|wc -l

2、查看每个php-fpm占用的内存大小

ps -ylC php-fpm --sort:rss

3、配置php-fpm参数

找到php-fpm的配置文件php-fpm.conf

pm = dynamic #对于专用服务器,pm可以设置为static。#如何控制子进程,选项有static和dynamic。如果选择static,则由pm.max_children指定固定的子进程数。如果选择dynamic,则由下开参数决定:
pm.max_children #子进程最大数
pm.start_servers #启动时的进程数
pm.min_spare_servers #保证空闲进程数最小值,如果空闲进程小于此值,则创建新的子进程
pm.max_spare_servers #保证空闲进程数最大值,如果空闲进程大于此值,此进行清理

对于内存大的服务器(比如8G以上)来说,指定静态的max_children实际上更为妥当,因为这样不需要进行额外的进程数目控制,会提高效率。

对于内存小的服务器,使用动态方式。具体最大数量根据 内存/20M 得到。比如512M的VPS,建议pm.max_spare_servers设置为20。至于pm.min_spare_servers,则建议根据服务器的负载情况来设置,比较合适的值在5~10之间。

解决Nginx php-fpm配置有误引起的502错误

在Ubuntu+Nginx+PHP环境下部署好以后,访问网站报错502,在后台nginx error_log里看到以下报错信息

2017/07/29 10:59:15 [error] 5622#0: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 183.14.134.39, server: xx.xx.xx.xx, request: “GET /index.php HTTP/1.1”, upstream: “fastcgi://127.0.0.1:9001”, host: “xx.xx.xx.xx”

通常这个报错是表示php-fpm这个服务未启动,由于默认是配置的9000端口,执行netstat -anp|grep 9000确实没有看到相关进程。

但执行命令查询php-fpm是running状态

# /etc/init.d/php7.0-fpm status
● php7.0-fpm.service – The PHP 7.0 FastCGI Process Manager
Loaded: loaded (/lib/systemd/system/php7.0-fpm.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2017-07-29 11:52:47 CST; 3h 43min ago
Process: 7191 ExecStartPre=/usr/lib/php/php7.0-fpm-checkconf (code=exited, status=0/SUCCESS)
Main PID: 7200 (php-fpm7.0)
Status: “Processes active: 0, idle: 2, Requests: 54, slow: 0, Traffic: 0req/sec”
CGroup: /system.slice/php7.0-fpm.service
├─7200 php-fpm: master process (/etc/php/7.0/fpm/php-fpm.conf)
├─7203 php-fpm: pool www
└─7204 php-fpm: pool www

Jul 29 11:52:47 iZwz96f0gkw4blayus6g2yZ systemd[1]: Starting The PHP 7.0 FastCGI Process Manager…
Jul 29 11:52:47 iZwz96f0gkw4blayus6g2yZ systemd[1]: Started The PHP 7.0 FastCGI Process Manager.

查看/etc/php/7.0/fpm/pool.d/www.conf和/etc/php/7.0/fpm/php-fpm.conf发现以下参数:

listen = /run/php/php7.0-fpm.sock

查阅资料后才知道,原来php-fpm支持网络端口监听和socket两种方式,但后者效率更高。

针对该问题的解决方案是,修改nginx/conf/vhosts下的conf文件,

将fastcgi_pass 127.0.0.1:9000;修改为fastcgi_pass unix:/run/php/php7.0-fpm.sock;

重启Nginx服务后,WEB访问依然报错502,继续定位分析。

在nginx error_log日志中出现了以下新的报错内容:

2017/07/29 11:24:47 [crit] 6114#0: *1 connect() to unix:/run/php/php7.0-fpm.sock failed (13: Permission denied) while connecting to upstream, client: 183.14.134.xx, server: 112.74.89.xx, request: “GET / HTTP/1.1”, upstream: “fastcgi://unix:/run/php/php7.0-fpm.sock:”, host: “112.74.89.xx”

然后找到/etc/php/7.0/fpm/pool.d/www.conf文件,做以下处理:

注释掉

;listen.owner = www-data
;listen.group = www-data

将mode值修改为0666

listen.mode = 0666

最后,执行/etc/init.d/php7.0-fpm restart重启php-fpm服务,执行/etc/init.d/nginx restart重启Nginx服务,问题解决!!!

nginx+lua实现简单的waf网页防火墙功能

Nginx+Lua实现WAF

安装LuaJIT

http://luajit.org/download/LuaJIT-2.0.4.tar.gz

tar xf LuaJIT-2.0.4.tar.gz

cd LuaJIT-2.0.4

make && make install 即可

下载ngx_devel_kit

https://codeload.github.com/simpl/ngx_devel_kit/zip/master

unzip ngx_devel_kit-master.zip

解压后的路径为:root/ngx_devel_kit-master

下载nginx_lua_module解压

https://github.com/openresty/lua-nginx-module#readme

unzip lua-nginx-module-master.zip

cd lua-nginx-module-master

安装nginx或给nginx打补丁

nginx -v 查看nginx的版本号

# nginx -v

nginx version: nginx/1.8.0

nginx -V 查看以前的编译参数

# nginx -V

nginx version: nginx/1.8.0

built by gcc 4.4.7 20120313 (Red Hat 4.4.7-16) (GCC) 

built with OpenSSL 1.0.1e-fips 11 Feb 2013

TLS SNI support enabled

configure arguments: --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_spdy_module --with-http_gzip_static_module --with-ipv6 --with-http_sub_module --with-google_perftools_module

我这里已经安装过nginx1.8了。

那么下面就是给nginx打补丁的事情了。如下:

进到nginx1.8的源代码目录下。执行下面的一系列命令:

# 导入环境变量,编译

# exportLUAJIT_LIB=/usr/local/lib    #这个很有可能不一样

# exportLUAJIT_INC=/usr/local/include/luajit-2.0 #这个很有可能不一样



# cd /home/tools/lnmp1.2-full/src/nginx-1.8.0

#./configure 

--user=www --group=www 

--prefix=/usr/local/nginx 

--with-http_stub_status_module 

--with-http_ssl_module 

--with-http_spdy_module 

--with-http_gzip_static_module 

--with-ipv6 

--with-http_sub_module 

--with-google_perftools_module 

--add-module=/root/ngx_devel_kit-master

--add-module=/root/lua-nginx-module-master

--with-ld-opt="-Wl,-rpath,$LUAJIT_LIB"



# make -j4 && make install

准备nginx的攻击日志目录

# mkdir -p /home/wwwlogs/attack

# chown www.www /home/wwwlogs/attack

# chmod -R 755 /home/wwwlogs/attack

安装nginx的Lua_waf模块

官方地址:https://github.com/loveshell/ngx_lua_waf

# wget https://codeload.github.com/loveshell/ngx_lua_waf/zip/master

# unzip ngx_lua_waf-master.zip

# cd ngx_lua_waf-master

# mkdir /usr/local/nginx/conf/waf

# cp -a ./ /usr/local/nginx/conf/waf

修改nginx的配置文件,在http段加入如下内容:

    lua_package_path"/usr/local/nginx/conf/waf/?.lua";

    lua_shared_dict limit 10m;  开启拦截cc攻击必须加这条规则

   init_by_lua_file /usr/local/nginx/conf/waf/init.lua;

   access_by_lua_file /usr/local/nginx/conf/waf/waf.lua;

修改/usr/local/nginx/conf/waf/config.lua中如下2部分内容即可:

RulePath ="/usr/local/nginx/conf/waf/wafconf/"

attacklog = "on"

logdir ="/home/wwwlogs/attack"

UrlDeny="on"

Redirect="on"

CookieMatch="on"

postMatch="on"

whiteModule="on"

black_fileExt={"php","jsp"}

ipWhitelist={"127.0.0.1"}

ipBlocklist={"1.0.0.1"}

CCDeny="on"

CCrate="100/60"




配置文件说明:

    RulePath = "/usr/local/nginx/conf/waf/wafconf/"    --规则存放目录

    attacklog = "off"               --是否开启攻击信息记录,需要配置logdir

    logdir ="/usr/local/nginx/logs/hack/"   --log存储目录,该目录需要用户自己新建,需要nginx用户的可写权限

    UrlDeny="on"                    --是否拦截url访问

    Redirect="on"                   --是否拦截后重定向

    CookieMatch = "on"              --是否拦截cookie攻击

    postMatch = "on"                --是否拦截post攻击

    whiteModule = "on"              --是否开启URL白名单

   black_fileExt={"php","jsp"}      --填写不允许上传文件后缀类型

    ipWhitelist={"127.0.0.1"}       --ip白名单,多个ip用逗号分隔

    ipBlocklist={"1.0.0.1"}          --ip黑名单,多个ip用逗号分隔

    CCDeny="on"           --是否开启拦截cc攻击(需要nginx.conf的http段增加lua_shared_dict limit 10m;)

    CCrate ="100/60"     --设置cc攻击频率,单位为秒. 默认1分钟同一个IP只能请求同一个地址100次

    html=[[Please go away~~]]       --警告内容,可在中括号内自定义

    备注:不要乱动双引号,区分大小写

重启nginx

# nginx -t

# /etc/init.d/nginx restart   重启nginx

恶意访问测试

# curl http://xxxx/test.php?id=../etc/passwd

# curl http://192.168.2.12/index.php?cmd=phpinfo();

或者直接在网页上请求

结果都是如下图所示,被拦截了。

未分类

此外,在/home/wwwlogs/attack目录下已经有日志文件记录下整个攻击的日志了。

未分类
未分类

一些说明:

过滤规则在wafconf下,可根据需求自行调整,每条规则需换行,或者用|分割

  • args里面的规则get参数进行过滤的

  • url是只在get请求url过滤的规则

  • post是只在post请求过滤的规则

  • whitelist是白名单,里面的url匹配到不做过滤

  • user-agent是对user-agent的过滤规则

默认开启了get和post过滤,需要开启cookie过滤的,编辑waf.lua取消部分–注释即可。

拦截到的非法请求,记录在日志文件名称格式如下:虚拟主机名_sec.log

说明:

这玩意貌似只能防止一些简单的sql注入类的语句,对于一些精心构造的恶意语句还是拦截不了的。

另外,我在公司的服务器上装了它,后台客服反应会出现form表单中图片无法上传的情况。

使用nginx+lua(openresty)实现waf功能

一、了解WAF

1.1 什么是WAF

Web应用防护系统(也称:网站应用级入侵防御系统 。英文:Web Application Firewall,简称: WAF)。利用国际上公认的一种说法:Web应用 防火墙 是通过执行一系列针对HTTP/HTTPS的 安全策略 来专门为Web应用提供保护的一款产品。

1.2 WAF的功能

  • 支持IP白名单和黑名单功能,直接将黑名单的IP访问拒绝。
  • 支持URL白名单,将不需要过滤的URL进行定义。
  • 支持User-Agent的过滤,匹配自定义规则中的条目,然后进行处理(返回403)。
  • 支持CC攻击防护,单个URL指定时间的访问次数,超过设定值,直接返回403。
  • 支持Cookie过滤,匹配自定义规则中的条目,然后进行处理(返回403)。
  • 支持URL过滤,匹配自定义规则中的条目,如果用户请求的URL包含这些,返回403。
  • 支持URL参数过滤,原理同上。
  • 支持日志记录,将所有拒绝的操作,记录到日志中去

1.3 WAF的特点

  • 异常检测协议
    Web应用防火墙会对HTTP的请求进行异常检测,拒绝不符合HTTP标准的请求。并且,它也可以只允许HTTP协议的部分选项通过,从而减少攻击的影响范围。甚至,一些Web应用防火墙还可以严格限定HTTP协议中那些过于松散或未被完全制定的选项。

未分类

  • 增强的输入验证
    增强输入验证,可以有效防止网页篡改、信息泄露、木马植入等恶意网络入侵行为。从而减小Web服务器被攻击的可能性。
  • 及时补丁
    修补Web安全漏洞,是Web应用开发者最头痛的问题,没人会知道下一秒有什么样的漏洞出现,会为Web应用带来什么样的危害。WAF可以为我们做这项工作了——只要有全面的漏洞信息WAF能在不到一个小时的时间内屏蔽掉这个漏洞。当然,这种屏蔽掉漏洞的方式不是非常完美的,并且没有安装对应的补丁本身就是一种安全威胁,但我们在没有选择的情况下,任何保护措施都比没有保护措施更好。
  • 基于规则的保护和基于异常的保护
    基于规则的保护可以提供各种Web应用的安全规则,WAF生产商会维护这个规则库,并时时为其更新。用户可以按照这些规则对应用进行全方面检测。还有的产品可以基于合法应用数据建立模型,并以此为依据判断应用数据的异常。但这需要对用户企业的应用具有十分透彻的了解才可能做到,可现实中这是十分困难的一件事情。
  • 状态管理
    WAF能够判断用户是否是第一次访问并且将请求重定向到默认登录页面并且记录事件。通过检测用户的整个操作行为我们可以更容易识别攻击。状态管理模式还能检测出异常事件(比如登陆失败),并且在达到极限值时进行处理。这对暴力攻击的识别和响应是十分有利的。
  • 其他防护技术
    WAF还有一些安全增强的功能,可以用来解决WEB程序员过分信任输入数据带来的问题。比如:隐藏表单域保护、抗入侵规避技术、响应监视和信息泄露保护。

1.3 WAF与网络防火墙的区别

网络防火墙作为访问控制设备,主要工作在OSI模型三、四层,基于IP报文进行检测。只是对端口做限制,对TCP协议做封堵。其产品设计无需理解HTTP会话,也就决定了无法理解Web应用程序语言如HTML、SQL语言。因此,它不可能对HTTP通讯进行输入验证或攻击规则分析。针对Web网站的恶意攻击绝大部分都将封装为HTTP请求,从80或443端口顺利通过防火墙检测。
  
一些定位比较综合、提供丰富功能的防火墙,也具备一定程度的应用层防御能力,如能根据TCP会话异常性及攻击特征阻止网络层的攻击,通过IP分拆和组合也能判断是否有攻击隐藏在多个数据包中,但从根本上说他仍然无法理解HTTP会话,难以应对如SQL注入、跨站脚本、cookie窃取、网页篡改等应用层攻击。
  
web应用防火墙能在应用层理解分析HTTP会话,因此能有效的防止各类应用层攻击,同时他向下兼容,具备网络防火墙的功能。

二、使用nginx配置简单实现403和404

2.1 小试身手之rerurn 403

修改nginx配置文件在server中加入以下内容

   set $block_user_agent 0;
if ( $http_user_agent ~ "Wget|AgentBench"){
   set $block_user_agent 1;
}
if ($block_user_agent = 1) {
   return 403 ;
}

通过其他机器去wget,结果如下

未分类

2.2 小试身手之rerurn 404

在nginx配置文件中加入如下内容,让访问sql|bak|zip|tgz|tar.gz的请求返回404

location ~* ".(sql|bak|zip|tgz|tar.gz)$"{
      return 404
    }

在网站根目录下放一个tar.gz

[root@iZ28t900vpcZ www]# tar zcvf abc.tar.gz wp-content/

通过浏览器访问结果如下,404已生效

未分类

三、深入实现WAF

3.1 WAF实现规划

分析步骤如下:解析HTTP请求==》匹配规则==》防御动作==》记录日志

具体实现如下:

  • 解析http请求:协议解析模块
  • 匹配规则:规则检测模块,匹配规则库
  • 防御动作:return 403 或者跳转到自定义界面
  • 日志记录:记录到elk中,画出饼图,建议使用json格式

未分类

3.2 安装nginx+lua

由于nginx配置文件书写不方便,并且实现白名单功能很复杂,nginx的白名单也不适用于CC攻击,所以在这里使用nginx+lua来实现WAF,如果想使用lua,须在编译nginx的时候配置上lua,或者结合OpenResty使用,此方法不需要编译nginx时候指定lua

3.2.1 编译nginx的时候加载

环境准备:Nginx安装必备的Nginx和PCRE软件包。

[root@nginx-lua ~]# cd /usr/local/src 
[root@nginx-lua src]# wget http://nginx.org/download/nginx-1.9.4.tar.gz
[root@nginx-lua src]# wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.37.tar.gz

其次,下载当前最新的luajit和ngx_devel_kit (NDK),以及春哥编写的lua-nginx-module

[root@nginx-lua src]# wget http://luajit.org/download/LuaJIT-2.0..tar.gz
[root@nginx-lua src]# wget https://github.com/simpl/ngx_devel_kit/archive/v0.2.19.tar.gz
[root@nginx-lua src]# wget https://github.com/openresty/lua-nginx-module/archive/v0.9.16.tar.gz

最后,创建Nginx运行的普通用户

[root@nginx-lua src]# useradd -s /sbin/nologin -M www

解压NDK和lua-nginx-module

[root@openstack-compute-node5 src]# tar zxvf v0.2.19.tar.gz
[root@openstack-compute-node5 src]# tar zxvf v0.9.16.tar.gz

安装LuaJIT Luajit是Lua即时编译器

[root@openstack-compute-node5 src]# tar zxvf LuaJIT-2.0.3.tar.gz 
[root@openstack-compute-node5 src]# cd LuaJIT-2.0.3
[root@openstack-compute-node5 LuaJIT-2.0.3]# make && make install

安装Nginx并加载模块

[root@openstack-compute-node5 src]# tar zxvf nginx-1.9.4.tar.gz 
[root@openstack-compute-node5 src]# cd nginx-1.9.4
[root@openstack-compute-node5 nginx-1.9.4]# export LUAJIT_LIB=/usr/local/lib
[root@openstack-compute-node5 nginx-1.9.4]# export LUAJIT_INC=/usr/local/include/luajit-2.0
[root@openstack-compute-node5 nginx-1.9.4]# ./configure --prefix=/usr/local/nginx --user=www --group=www     --with-http_ssl_module --with-http_stub_status_module --with-file-aio --with-http_dav_module --add-module=../ngx_devel_kit-0.2.19/ --add-module=../lua-nginx-module-0.9.16/ --with-pcre=/usr/local/src/pcre-8.37 
[root@openstack-compute-node5 nginx-1.5.12]# make -j2 && make install
[root@openstack-compute-node5 ~]# ln -s /usr/local/lib/libluajit-5.1.so.2 /lib64/libluajit-5.1.so.2   #一定创建此软连接,否则报错

安装完毕后,下面可以测试安装了,修改nginx.conf 增加第一个配置

location /hello {
                default_type 'text/plain';
                content_by_lua 'ngx.say("hello,lua")';
        }
[root@openstack-compute-node5 ~]# /usr/local/nginx-1.9.4/sbin/nginx –t
[root@openstack-compute-node5 ~]# /usr/local/nginx-1.9.4/sbin/nginx

效果如下

未分类

3.2.3 Openresty部署

安装依赖包

[root@iZ28t900vpcZ ~]#yum install -y readline-devel pcre-devel openssl-devel

下载并编译安装openresty

[root@iZ28t900vpcZ ~]#cd /usr/local/src
[root@iZ28t900vpcZ src]#wget https://openresty.org/download/ngx_openresty-1.9.3.2.tar.gz
[root@iZ28t900vpcZ src]#tar zxf ngx_openresty-1.9.3.2.tar.gz
[root@iZ28t900vpcZ src]#cd ngx_openresty-1.9.3.2
[root@iZ28t900vpcZ ngx_openresty-1.9.3.2]# ./configure --prefix=/usr/local/openresty-1.9.3.2 --with-luajit --with-http_stub_status_module --with-pcre --with-pcre-jit
[root@iZ28t900vpcZ ngx_openresty-1.9.3.2]#gmake && gmake install
ln -s /usr/local/openresty-1.9.3.2/ /usr/local/openresty

测试openresty安装

[root@iZ28t900vpcZ ~]#vim /usr/local/openresty/nginx/conf/nginx.conf
server {
    location /hello {
            default_type text/html;
            content_by_lua_block {
                ngx.say("HelloWorld")
            }
        }
}

测试并启动nginx

[root@iZ28t900vpcZ ~]#/usr/local/openresty/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/openresty-1.9.3.2/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/openresty-1.9.3.2/nginx/conf/nginx.conf test is successful
[root@iZ28t900vpcZ ~]#/usr/local/openresty/nginx/sbin/nginx

3.2.4 WAF部署

在github上克隆下代码

[root@iZ28t900vpcZ ~]#git clone https://github.com/unixhot/waf.git
[root@iZ28t900vpcZ ~]#cp -a ./waf/waf /usr/local/openresty/nginx/conf/

修改Nginx的配置文件,加入(http字段)以下配置。注意路径,同时WAF日志默认存放在/tmp/日期_waf.log

#WAF
    lua_shared_dict limit 50m;  #防cc使用字典,大小50M
    lua_package_path "/usr/local/openresty/nginx/conf/waf/?.lua";
    init_by_lua_file "/usr/local/openresty/nginx/conf/waf/init.lua";
    access_by_lua_file "/usr/local/openresty/nginx/conf/waf/access.lua";
[root@openstack-compute-node5 ~]# /usr/local/openresty/nginx/sbin/nginx –t
[root@openstack-compute-node5 ~]# /usr/local/openresty/nginx/sbin/nginx

根据日志记录位置,创建日志目录

[root@iZ28t900vpcZ ~]#mkdir /tmp/waf_logs
[root@iZ28t900vpcZ ~]#chown nginx.nginx /tmp/waf_logs

3.3 学习模块

3.3.1 学习配置模块

WAF上生产之前,建议不要直接上生产,而是先记录日志,不做任何动作。确定WAF不产生误杀

config.lua即WAF功能详解

[root@iZ28t900vpcZ waf]# pwd
/usr/local/nginx/conf/waf
[root@iZ28t900vpcZ waf]# cat config.lua
--WAF config file,enable = "on",disable = "off" 
--waf status    
config_waf_enable = "on"   #是否开启配置
--log dir 
config_log_dir = "/tmp/waf_logs"    #日志记录地址
--rule setting 
config_rule_dir = "/usr/local/nginx/conf/waf/rule-config"                                                                  
                         #匹配规则缩放地址
--enable/disable white url 
config_white_url_check = "on"  #是否开启url检测
--enable/disable white ip 
config_white_ip_check = "on"   #是否开启IP白名单检测
--enable/disable block ip 
config_black_ip_check = "on"   #是否开启ip黑名单检测
--enable/disable url filtering 
config_url_check = "on"      #是否开启url过滤
--enalbe/disable url args filtering 
config_url_args_check = "on"   #是否开启参数检测
--enable/disable user agent filtering 
config_user_agent_check = "on"  #是否开启ua检测
--enable/disable cookie deny filtering 
config_cookie_check = "on"    #是否开启cookie检测
--enable/disable cc filtering 
config_cc_check = "on"   #是否开启防cc攻击
--cc rate the xxx of xxx seconds 
config_cc_rate = "10/60"   #允许一个ip60秒内只能访问10此
--enable/disable post filtering 
config_post_check = "on"   #是否开启post检测
--config waf output redirect/html 
config_waf_output = "html"  #action一个html页面,也可以选择跳转
--if config_waf_output ,setting url 
config_waf_redirect_url = "http://www.baidu.com" 
config_output_html=[[  #下面是html的内容
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<meta http-equiv="Content-Language" content="zh-cn" /> 
<title>网站防火墙</title> 
</head> 
<body> 
<h1 align="center"> # 您的行为已违反本网站相关规定,注意操作规范。
</body> 
</html> 
]] 

3.4 学习access.lua的配置

[root@iZ28t900vpcZ waf]# pwd
/usr/local/openresty/nginx/conf/waf
[root@iZ28t900vpcZ waf]# cat access.lua 
require 'init'
function waf_main()
    if white_ip_check() then
    elseif black_ip_check() then
    elseif user_agent_attack_check() then
    elseif cc_attack_check() then
    elseif cookie_attack_check() then
    elseif white_url_check() then
    elseif url_attack_check() then
    elseif url_args_attack_check() then
    --elseif post_attack_check() then
    else
        return  
    end
end
waf_main()

书写书序:先检查白名单,通过即不检测;再检查黑名单,不通过即拒绝,检查UA,UA不通过即拒绝;检查cookie;URL检查;URL参数检查,post检查;

3.5 启用WAF并测试

3.5.1模拟sql注入即url攻击

显示效果如下

未分类

日志显示如下,记录了UA,匹配规则,URL,客户端类型,攻击的类型,请求的数据

未分类

3.5.2 使用ab压测工具模拟防cc攻击

[root@linux-node3 ~]# ab -c 100 -n 100 http://www.chuck-blog.com/index.php
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking www.chuck-blog.com (be patient).....done
Server Software:        openresty
Server Hostname:        www.chuck-blog.com
Server Port:            80
Document Path:          /index.php
Document Length:        0 bytes
Concurrency Level:      100
Time taken for tests:   0.754 seconds
Complete requests:      10
Failed requests:        90 #config.lua中设置的,60秒内只允许10个请求
Write errors:           0
Non-2xx responses:      90
Total transferred:      22700 bytes
HTML transferred:       0 bytes
Requests per second:    132.65 [#/sec] (mean)
Time per request:       753.874 [ms] (mean)
Time per request:       7.539 [ms] (mean, across all concurrent requests)
Transfer rate:          29.41 [Kbytes/sec] received
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       23   69  20.2     64     105
Processing:    32  180 144.5    157     629
Waiting:       22  179 144.5    156     629
Total:         56  249 152.4    220     702
Percentage of the requests served within a certain time (ms)
  50%    220
  66%    270
  75%    275
  80%    329
  90%    334
  95%    694
  98%    701
  99%    702
  100%    702 (longest request)

3.5.3 模拟ip黑名单
将请求ip放入ip黑名单中

[root@iZ28t900vpcZ rule-config]# echo “1.202.193.133” >>/usr/local/openresty/nginx/conf/waf/rule-config/blackip.rule

3.5.4 模拟ip白名单
将请求ip放入ip白名单中,此时将不对此ip进行任何防护措施,所以sql注入时应该返回404

[root@iZ28t900vpcZ rule-config]# echo “1.202.193.133” >>/usr/local/openresty/nginx/conf/waf/rule-config/whiteip.rule

3.5.5 模拟URL参数检测
浏览器输入www.chuck-blog.com/?a=select * from table
详细规定在arg.rule中有规定,对请求进行了规范

[root@iZ28t900vpcZ rule-config]# /usr/local/openresty/nginx/conf/waf/rule-config/cat args.rule 
../
:$
${
select.+(from|limit)
(?:(union(.*?)select))
having|rongjitest
sleep((s*)(d*)(s*))
benchmark((.*),(.*))
base64_decode(
(?:fromW+information_schemaW)
(?:(?:current_)user|database|schema|connection_id)s*(
(?:etc/W*passwd)
into(s+)+(?:dump|out)files*
groups+by.+(
xwork.MethodAccessor
    (?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)(
xwork.MethodAccessor
    (gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data):/
java.lang
    $_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)[
    <(iframe|script|body|img|layer|div|meta|style|base|object|input)
(onmouseover|onerror|onload)=
[root@iZ28t900vpcZ rule-config]# pwd
/usr/local/openresty/nginx/conf/waf/rule-config

四、防cc攻击利器之httpgrard

4.1 httpgrard介绍

HttpGuard是基于openresty,以lua脚本语言开发的防cc攻击软件。而openresty是集成了高性能web服务器Nginx,以及一系列的Nginx模块,这其中最重要的,也是我们主要用到的nginx lua模块。HttpGuard基于nginx lua开发,继承了nginx高并发,高性能的特点,可以以非常小的性能损耗来防范大规模的cc攻击。

4.2 httpgrard防cc特效

  • 限制访客在一定时间内的请求次数
  • 向访客发送302转向响应头来识别恶意用户,并阻止其再次访问
  • 向访客发送带有跳转功能的js代码来识别恶意用户,并阻止其再次访问
  • 向访客发送cookie来识别恶意用户,并阻止其再次访问
  • 支持向访客发送带有验证码的页面,来进一步识别,以免误伤
  • 支持直接断开恶意访客的连接
  • 支持结合iptables来阻止恶意访客再次连接
  • 支持白名单功能
  • 支持根据统计特定端口的连接数来自动开启或关闭防cc模式
  • 详见github地址,在后续的博文中会加入此功能

五、WAF上线

  • 初期上线只记录日志,不开启WAF,防止误杀
  • WAF规则管理使用saltstack工具
  • 要知道并不是有了WAF就安全,存在人为因素