通过NGINX配置文件防止XMLRPC.PHP攻击

最近在博客后台发现有一些ip的访问量特别大,排查nginx日志发现基本都是xmlrpc攻击

xmlrpc.php攻击可以绕过使用用户名登陆限制,进行暴力破解。在不想修改wordpress代码的情况下,使用nginx限制是最好的办法。

不建议删除xmlrpc.php文件,因为可能造成莫名其妙的错误

  • 方法1

nginx直接禁止访问该文件

location ~* /xmlrpc.php {
  deny all;
}
  • 方法2

通过跳转或重定向转移流量,这样可以引流到你希望引流到目标的网址或者ip

location ~* /xmlrpc.php {
  proxy_pass https://www.baidu.com;
}

使用nginx replace-filter-nginx-module模块替换网页中的http链接为https

首先不知道openresty为何物的,可自行google!

问题:我们有一个网站,开始用的是http协议的,由于历史原因,路径写在各个地方,比较混乱。现在想启用https协议,可是现在的浏览器不充计https协议下加载http协议的样式,脚本等。

方案1: 将代码中的http全部修改成https,工作量比较大,并且风险太高

方案2: 在程序的输出到时,统一替换,这个虽然相对不错,不过感觉还是有点麻烦,把不属于业务的功能放到了业务代码上

方案3: 在web服务器上做统一替换,这也是我们最终决定的方案,我们选用openresty来做统一替换功能.

安装:

cd /opt/
yum install readline-devel pcre-devel openssl-devel gcc
wget https://openresty.org/download/ngx_openresty-1.9.7.1.tar.gz
git clone https://github.com/openresty/sregex.git
git clone https://github.com/openresty/replace-filter-nginx-module.git
cd  sregex
make
make install
cd ..
tar -zxvf ngx_openresty-1.9.7.1.tar.gz
cd ngx_openresty-1.9.7.1
./configure --with-luajit --add-module=/opt/replace-filter-nginx-module/ --with-debug
gmake
gmake install

这样openresty就算安装完毕,默认安装在/usr/local/openresty。

配置如下:

mkdir /usr/local/openresty/test
cd /usr/local/openresty/test
mkdir logs/ conf/

//在conf目录下创建一个文本文件作为配置文件,命名为nginx.conf

worker_processes  1;
error_log logs/error.log debug;
events {
    worker_connections 1024;
}
http {
    server {
        root            /alidata/www/test;
        index           index.php;
        charset         utf-8;
        server_name     test.xxx.com;
        listen          80;

        rewrite ^/(.*) https://$server_name/$1 permanent;    #跳转到Https

    }
    server {
        root            /alidata/www/test;
        index           index.php;
        charset         utf-8;
        server_name     test.xxx.com;
        listen          443;

        replace_filter 'http://test.xxx.com' 'https://test.xxx.com' 'ig';
        replace_filter 'http://(d+).gravatar.com' 'https://$1.gravatar.com' 'ig';
    }
}

写一shell来start,stop,reload

start.sh

#!/bin/bash
/usr/local/openresty/nginx/sbin/nginx -p /usr/local/openresty/test -c conf/nginx.conf

stop.sh

#!/bin/bash
/usr/local/openresty/nginx/sbin/nginx -p /usr/local/openresty/test -c conf/nginx.conf -s stop

reload.sh

#!/bin/bash
/usr/local/openresty/nginx/sbin/nginx -p /usr/local/openresty/test -c conf/nginx.conf -s stop

总结:

通过这样简单的配置,我们就成功实现了将响应中的内容替换了,还是蛮方便的!

Ubuntu14.04系统安装配置Nginx+PHP+MySQL+EduSoho

注意: 本教程基于Ubuntu系统 14.04版本并且需要以root用户操作机器,请在确保您的环境是否符合以上两个条件之后,再进行后续的操作。

切记:我们的edusoho访问目录是edusoho/web,只有在nginx或者Apache配
置里面把根目录定位到web目录下,才不会出现奇怪的问题,否则就会出现图片不能显示或者文件无法上传的问题。

本教程主要分为一下几个步骤:更新系统、安装并配置Nginx、安装MySQL、安装并配置PHP、 安装并配置EduSoho,测试Edusoho。

一、更新系统

sudo apt-get update
sudo apt-get upgrade

二、安装Nginx

1、安装nginx

sudo apt-get install nginx

2、配置Nginx

sudo vim /etc/nginx/nginx.conf 
然后 在http{} 字段里添加
client_max_body_size 1024M;

三、安装并配置MySQL

1、安装mysql

apt-get install mysql-server

在这个过程过程中会要求您输入MySQL数据库的root密码,请认真填写。

2、创建数据库

mysql -uroot -p 

然后你需要输入MySQL数据库的root密码。

进入数据库命令行模式后,创建edusoho数据库,执行:

CREATE DATABASE `edusoho` DEFAULT CHARACTER SET utf8 ; 
GRANT ALL PRIVILEGES ON `edusoho`.* TO 'esuser'@'localhost' IDENTIFIED BY 'edusoho';
quit;

注意:这里为edusoho数据库创建了一个用户名,用户名为:esuser,密码为edusoho,在后面安装的第三步需要用到,不建议直接填写root账户。

四、安装PHP

1、安装PHP

sudo apt-get install php5 php5-cli php5-curl php5-fpm php5-intl php5-mcrypt php5-mysqlnd php5-gd

2、修改PHP上传文件的大小限制

sudo vim /etc/php5/fpm/php.ini

添加一下三行配置文字

post_max_size = 1024M 
memory_limit = 1024M
upload_max_filesize = 1024M

3、配置PHP-FPM

编辑配置文件: vim /etc/php5/fpm/pool.d/www.conf,找到:

;listen.owner = www-data
;listen.group = www-data
;listen.mode = 0660
去除最前面的分号。

然后重启PHP-FPM:
sudo /etc/init.d/php5-fpm restart

五、配置安装EduSoho

1、下载/解压程序

mkdir /var/www
cd /var/www
wget http://download.edusoho.com/edusoho-VERSION.tar.gz  (注:将VERSION替换为当前EduSoho最新版本号,可从官网www.edusoho.com查询获取)
tar -zxvf edusoho-VERSION.tar.gz
chown www-data:www-data edusoho/ -Rf
注:这里的下载地址可以在http://www.edusoho.com/中可以获取到,VERSION为下载来之后压缩包后面的版本号。

2、配置nginx的虚拟主机

sudo vim /etc/nginx/sites-enabled/edusoho

输入以下内容:

server {
    listen 80;

    # [改] 网站的域名
    server_name www.example.com example.com;

    #301跳转可以在nginx中配置

    # 程序的安装路径
    root /var/www/edusoho/web;

    # 日志路径
    access_log /var/log/nginx/example.com.access.log;
    error_log /var/log/nginx/example.com.error.log;

    location / {
        index app.php;
        try_files $uri @rewriteapp;
    }

    location @rewriteapp {
        rewrite ^(.*)$ /app.php/$1 last;
    }

    location ~ ^/udisk {
        internal;
        root /var/www/edusoho/app/data/;
    }

    location ~ ^/(app|app_dev).php(/|$) {
        fastcgi_pass   unix:/var/run/php5-fpm.sock;
        fastcgi_split_path_info ^(.+.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
        fastcgi_param  HTTPS              off;
        fastcgi_param HTTP_X-Sendfile-Type X-Accel-Redirect;
        fastcgi_param HTTP_X-Accel-Mapping /udisk=/var/www/edusoho/app/data/udisk;
        fastcgi_buffer_size 128k;
        fastcgi_buffers 8 128k;
    }

    # 配置设置图片格式文件
    location ~* .(jpg|jpeg|gif|png|ico|swf)$ {
        # 过期时间为3年
        expires 3y;

        # 关闭日志记录
        access_log off;

        # 关闭gzip压缩,减少CPU消耗,因为图片的压缩率不高。
        gzip off;
    }

    # 配置css/js文件
    location ~* .(css|js)$ {
        access_log off;
        expires 3y;
    }

    # 禁止用户上传目录下所有.php文件的访问,提高安全性
    location ~ ^/files/.*.(php|php5)$ {
        deny all;
    }

    # 以下配置允许运行.php的程序,方便于其他第三方系统的集成。
    location ~ .php$ {
        # [改] 请根据实际php-fpm运行的方式修改
        fastcgi_pass   unix:/var/run/php5-fpm.sock;
        fastcgi_split_path_info ^(.+.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
        fastcgi_param  HTTPS              off;
        fastcgi_param  HTTP_PROXY         "";
    }
}

配置文件中的example.com 为您需要指定的域名,为了确保您的域名能被他人访问得到, 您需要将这个域名和您当前的机器IP地址做DNS解析工作。

3、重启nginx

sudo /etc/init.d/nginx restart

最后一步:

浏览器中打开:http://YOU_DOMAIN 安装,当然这里的YOU_DOMAIN是您的域名。

Nginx下配置ThinkPHP URL的PATHINFO与REWRITE

尝试了下 ThinkPHP 框架, 版本为 3.2.3, 测试环境为 Windows 下 Nginx 1.6 + PHP 5.5。本文内容为解决 Nginx 下 ThinkPHP URL 模式中所用到的 PATHINFO 与 REWRITE 模式的配置问题。并在 Mac OS X 10.10 下 Nginx 1.8.0 + PHP 5.6.8 下测试通过。理论同样适用于各版本的 Linux 系统中。

PATHINFO 与 REWRITE 模式在表现上的不同在于浏览器的 URL 地址栏中, 以访问 Home 模块, User 控制器, login 操作为例:

PATHINFO 下的 URL: http://localhost/index.php/Home/User/login
REWRITE 下的 URL: http://localhost/Home/User/login

Nginx 开启 PATHINFO

在这之前, 笔者也到搜索引擎上看了几篇关于 Nginx 配置 PATHINFO 的方法, 感觉有点乱, 乱的原因主要是由于 Nginx 没有给予像 Apache 那样一个参数即可开启 PATHINFO 的良好支持, 因此出现了各种 Nginx 下开启 PATHINFO 的解法。

这里提供的是参阅 Nginx 官方文档并结合实测可用后的 PATHINFO 的方案。去除不必须的注释, Nginx 开启 PATHINFO 的 server 部分配置如下:

server {
 listen       80;
 server_name  localhost;
 location / {
   root   D:/Projects/Demo/thinkphp;   # 你的 TP 框架 index.php 所在目录, 记得用 / 分割路径
   index index.php index.html index.htm;
 }
 # ...
 # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
 #
 location ~ ^(.+.php)(.*)$ {
   root   D:/Projects/Demo/thinkphp;   # 你的 TP 框架 index.php 所在目录, 记得用 / 分割路径
   fastcgi_split_path_info ^(.+.php)(.*)$;
   fastcgi_param PATH_INFO $fastcgi_path_info;
   fastcgi_pass   127.0.0.1:9000;
   fastcgi_index  index.php;
   fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
   include        fastcgi_params;
 }
}

这种做法的原理是当请求的访问路径中含有 .php 时, 通过正则表达式构造出 PATHINFO, 并设置到 fastcgi 的参数 PATH_INFO 中。

代码中匹配 PATH_INFO 的正则表达式来源于 Nginx 官方文档中的写法。参见: http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_split_path_info

PATHINFO 模式是 ThinkPHP 默认的 URL 模式, 因此不需要修改 ThinkPHP 的默认配置即可使用 http://serverName/index.php/模块/控制器/操作 方式访问。

URL REWRITE 模式

REWRITE 模式也称 URL重写, 可用于隐藏 PATHINFO 模式路径中的 index.php, 开启 REWRITE 模式的 Nginx 配置为:

server {
 listen       80;
 server_name  localhost;
 location / {
   root   D:/Projects/Demo/thinkphp;   # 你的 TP 框架 index.php 所在目录, 记得用 / 分割路径
   index index.php index.html index.htm;
   try_files $uri $uri/ /index.php?s=$uri; # 核心
 }
 # ...
 # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
 #
 location ~ .php$ {
   root   D:/Projects/Demo/thinkphp;   # 你的 TP 框架 index.php 所在目录, 记得用 / 分割路径
   fastcgi_pass   127.0.0.1:9000;
   fastcgi_index  index.php;
   fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
   include        fastcgi_params;
 }
}

配置完成后修改 ThinkPHP 的 URL 模式为 REWRITE, 编辑配置文件 ThinkPHP/Conf/convention.php 中修改 URL_MODEL 参数值为 2 (REWRITE 模式)即可通过 http://serverName/模块/控制器/操作 方式访问。

ubuntu16.04使用nginx、uwsgi部署django应用

安装相关软件

更新源

sudo apt-get update 
sudo apt-get upgrade

安装虚拟环境

sudo apt-get install Python-virtualenv

安装nginx

sudo apt-get install nginx

安装uwsgi

sudo pip3 install uwsgi

或者

sudo pip3 install https://projects.unbit.it/downloads/uwsgi-lts.tar.gz

安装uwsgi出错就安装

sudo apt-get install python-dev 
sudo apt-get install python3.5-dev

本文用到的软件环境

  • ubuntu 16.04
  • Python 3.5.2
  • Django 1.11.4
  • nginx 1.10.3
  • uwsgi 2.0.15

创建一个普通用户

创建用户组webapps

sudo groupadd –system webapps

创建用户user_test并设置密码

sudo useradd –system –gid webapps –shell /bin/bash –home /webapps/test user_test

passwd user_test

创建用户目录并修改目录权限

mkdir -p /webapps/test

chown user_test /webapps/test/

添加用户user_test sudo权限

在/etc/sudoers添加

user_test ALL=(ALL:ALL) ALL

创建测试应用

切换用户为user_test

su - user_test

cd /webapps/test

创建python虚拟环境,这里指定为3.5版本,并激活

virtualenv -p /usr/bin/python3.5 .

source bin/activate

安装django

pip install django

创建django工程mysite

django-admin startproject mysite

创建应用app

cd mysite

django-admin startapp app

修改mysite/settings.py

将外网ip添加到ALLOWED_HOSTS

ALLOWED_HOSTS = ['xxx.xxx.xxx.xxx', '127.0.0.1']

在INSTALLED_APPS里追加 ‘app’

新建app/static目录

在mysite/settings.py里添加

STATIC_ROOT = os.path.join(BASE_DIR, 'app', 'static')

收集静态文件到app/static目录

python manage.py collectstatic

迁移数据库

python manage.py migrate

创建后台管理用户

python manage.py createsuper

添加视图函数

在app/views.py添加

from django.http import HttpResponse
def index(request):
    return HttpResponse('<h1>Hello World!</h1>')

在mysite/urls.py添加

from app import views
urlpatterns = [
    ...
    url(r'^$', views.index),
]

测试django应用运行是否正常

python manage.py runserver

使用curl命令访问

curl 127.0.0.1:8000

正常会输出 <h1>Hello World!</h1>

Ctrl C 退出

当前所涉及的一些目录

  • 用户目录:/webapps/test
  • 虚拟环境目录: /webapps/test
  • 工程目录:/webapps/test/mysite

配置ngnix

从https://github.com/nginx/nginx/blob/master/conf/uwsgi_params下载到/etc/nginx/conf/目录

新建mysite/test_ngnix.conf文件,内容如下

# the upstream component nginx needs to connect to
upstream testapp {
    server unix:///webapps/test/mysite/mysite.sock; # for a file socket
    #server 127.0.0.1:9090; # for a web port socket (we'll use this first)
}

# configuration of the server
server {
    # the port your site will be served on
    listen      80;
    # the domain name it will serve for
    server_name localhost; # substitute your machine's IP address or FQDN
    charset     utf-8;

    # max upload size
    client_max_body_size 75M;   # adjust to taste
    access_log      /webapps/test/mysite/nginx_access.log;
    error_log       /webapps/test/mysite/nginx_error.log;

    # Django media
    location /media  {
        alias /webapps/test/mysite/app/media;  # your Django project's media files - amend as required
    }

    location /static {
        alias /webapps/test/mysite/app/static; # your Django project's static files - amend as required
    }

    # Finally, send all non-media requests to the Django server.
    location / {
        uwsgi_pass  testapp;
        include     /etc/nginx/conf/uwsgi_params; # the uwsgi_params file you installed
    }
}

将test_ngnix.conf链接到/etc/nginx/sites-enabled/目录

sudo ln -s /webapps/test/mysite/test_ngnix.conf /etc/nginx/sites-enabled/

记得删除自带的default文件,否则输入外网ip看到的是ngnix欢迎页

sudo rm /etc/nginx/sites-enabled/default

这里用到的是unix file socket

所以把用户www-data加到webapps用户组,否则读取socket文件时会有权限问题

sudo usermod -a -G webapps www-data

重启ngnix

sudo /etc/init.d/nginx stop 
sudo /etc/init.d/nginx start

配置uwsgi

新建wsgi.ini, 内容如下

[uwsgi]
#socket = 127.0.0.1:9090
chdir=/webapps/test/mysite
module=mysite.wsgi
master = true
processes=2
threads=2
max-requests=2000
chmod-socket=664
vacuum=true
daemonize = /webapps/test/mysite/uwsgi.log
virtualenv = /webapps/test
gid=webapps
uid=user_test
socket = /webapps/test/mysite/mysite.sock

运行uwsgi

uwsgi –ini wsgi.ini

用浏览器访问外网ip,正常会显示Hello World

使用uwsgi Emperor mode

# create a directory for the vassals
sudo mkdir /etc/uwsgi
sudo mkdir /etc/uwsgi/vassals
# symlink from the default config directory to your config file
sudo ln -s /webapps/test/mysite/wsgi.ini /etc/uwsgi/vassals/
# run the emperor
sudo uwsgi --emperor /etc/uwsgi/vassals --uid user_test --gid webapps

Ubuntu安装配置uWSGI Nginx部署Flask项目

关于 uWSGI ,可以先看这篇文章。简单来说,WSGI 是一个 Python 协议,定义了应用程序(我们写的软件)如何与 Web 服务器(如 Nginx)通信,WSGI 只是一个接口。而 uWSGI 是一个支持多种语言的服务器容器,使用 WSGI 定义的标准实现与多种 Web 服务器的通信,并将 Web 服务器发来的请求“翻译”成应用程序所能理解形式。

安装

Python 2:

sudo apt-get update
sudo apt-get install python-pip python-dev nginx

Python 3:

sudo apt-get update
sudo apt-get install python3-pip python3-dev nginx

安装 Flask 和 uwsgi:

pip install uwsgi flask

创建一个简单的 Flask 项目 ~/myproject/myproject.py:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "<h1 style='color:blue'>Hello There!</h1>"

if __name__ == "__main__":
    app.run(host='0.0.0.0')

创建启动文件为 ~/myproject/run.py:

from myproject import app

if __name__ == "__main__":
    app.run()

运行 python run.py ,然后访问 http://server_domain_or_IP:5000 将会看到:

未分类

当然直接使用 python run.py 的方法只适合本地开发,线上的话速度太慢,我们需要使用 uwsgi。

uwsgi

首先确保你安装了 uwsgi,然后运行:

uwsgi --socket 0.0.0.0:5000 --protocol=http -w run:app

protocol 说明使用 http 协议,-w 指明了要启动的模块,run 就是项目启动文件 run.py 去掉扩展名,app 是 run.py 文件中的变量 app,即 Falsk 实例。然后访问 http://server_domain_or_IP:5000,同样会看到上图。说明 uwsgi 可以正常运行。

但是这样的话每次都从命令行启动太麻烦,可以在 ~/myproject/目录下创建一个配置文件 myproject.ini:

[uwsgi]
module = run:app
master = true
processes = 3

chdir = /home/ubuntu/myproject
socket = /path/to/sock/myproject.sock
logto = /home/to/log/ishuhui.log
chmod-socket = 660
vacuum = true
  • processes = 5 说明要启动5个子进程处理请求;module = run:app 和命令行使用的意义一样;
  • chdir = /home/ubuntu/myproject 只想我们项目的根目录,即 run.py 所在文件夹;
  • socket = /path/to/sock/myproject.sock 是 uwsgi 启动后所需要创建的文件,这个文件用来和 Nginx 通信,后面会在配置 Nginx 时用到,所以 chmod-socket = 660 是为了修改 .sock 文件权限来和 Nginx 通信;
  • logto = /home/to/log/ishuhui.log 指明了 uwsgi 日志目录,uwsgi 会将请求历史写入该文件。

配置完成后运行:

uwsgi --ini myproject.ini

可以看到 /path/to/sock/myproject.sock 目录下多了 myproject.sock 文件,用来和 Nginx 通信。接下来配置 Nginx。

配置 Nginx

配置 Nginx 特别简单,找到 Nginx 配置文件(sudo vim /etc/nginx/sites-available/default),修改为如下格式:

server {
    listen 80;
    server_name server_domain_or_IP;

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/path/to/sock/myproject.sock;
    }
}

其实重要的就两行:

include uwsgi_params;
uwsgi_pass unix:/path/to/sock/myproject.sock;

接下来不出意外,访问 80 端口,就可以看到你的程序了。

将 uwsgi 设置为系统服务

我们运行 uwsgi –ini myproject.ini 之后,按 ctrl+c 或者关闭 ssh 连接窗口,都会导致 uwsgi 进程关闭。 uwsgi 进程一关闭,.sock 文件就会消失,这时访问网站 Nginx 就会报错:

未分类

这时,我们需要进程管理软件管理 uwsgi 进程的运行了。Ubuntu 自带的 systemd 是最简单的方法,可以将我们的项目变为系统服务。首先创建 myproject.service 文件 sudo vim /etc/systemd/system/myproject.service:

[Unit]
Description=uWSGI instance to serve myproject
After=network.target

[Service]
User=lufficc
Group=www-data
WorkingDirectory=/home/ubuntu/myproject
Environment=FLASKR_SETTINGS=/home/ubuntu/myproject/env.cfg
ExecStart=/usr/local/bin/uwsgi --ini /home/ubuntu/myprojectenv/ishuhui.ini

[Install]
WantedBy=multi-user.target
  • WorkingDirectory: 你的项目目录。
  • Environment:需要的环境变量,比如指明你的项目的配置文件。
  • ExecStart:服务启动的代码。
  • WantedBy=multi-user.target:指明会跟随系统启动而启动该服务。

注意以上所有路径为绝对路径。

接下来可以愉快的启动了(myproject 就是 myproject.service 文件名去掉扩展名):

sudo systemctl start myproject
sudo systemctl restart myproject
sudo systemctl stop myproject

nginx 1.13.3编译安装ngx_lua_waf安全防护

未分类

前言

ngx_lua_waf是一个基于ngx_lua的web应用防火墙,使用简单,高性能和轻量级。

  • 防止sql注入,本地包含,部分溢出,fuzzing测试,xss,SSRF等web攻击

  • 防止svn/备份之类文件泄漏

  • 防止ApacheBench之类压力测试工具的攻击

  • 屏蔽常见的扫描黑客工具,扫描器

  • 屏蔽异常的网络请求

  • 屏蔽图片附件类目录php执行权限

  • 防止webshell上传

准备

ngx_lua_waf推荐使用Luajit做lua支持,而Luajit需要ngx_devel_kit模块与lua-nginx-module模块。进入/usr/local/src目录准备以上文件。

1、下载ngx_devel_kit

wget https://github.com/simpl/ngx_devel_kit/archive/v0.3.0.tar.gz
tar zxvf v0.3.0.tar.gz

2、下载lua-nginx-module

wget https://github.com/openresty/lua-nginx-module/archive/v0.10.10.tar.gz
tar zxvf v0.10.10.tar.gz

3、安装Lua环境

wget http://luajit.org/download/LuaJIT-2.0.3.tar.gz
tar xf LuaJIT-2.0.5.tar.gz
cd LuaJIT-2.0.5
make && sudo make install

编译

1、进入Nginx安装目录:

cd /usr/local/src/nginx-1.13.3

2、导入环境变量

#这个很有可能不一样
export LUAJIT_LIB=/usr/local/lib
#这个很有可能不一样
export LUAJIT_INC=/usr/local/include/luajit-2.0

3、查看目前Nginx的版本

nginx -V

4、加载模块

./configure(Nginx-V已有的模块)--add-module=/usr/local/src/ngx_devel_kit-0.3.0 --add-module=/usr/local/src/lua-nginx-module-0.10.10 --with-ld-opt=-Wl,-rpath,$LUAJIT_LIB

5、编译参数

# 注意不要make install
make
#重命名nginx旧版本二进制文件
mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old
#拷贝一份新编译的二进制文件
cp objs/nginx /usr/local/nginx/sbin/
#升级
make upgrade
#确认
nginx -V
#重新加载Nginx
nginx -s reload

安装

1、准备Luajit

从https://github.com/loveshell/ngx_lua_waf下载Luajit。

nginx安装路径假设为/usr/local/nginx/,把ngx_lua_waf下载到conf目录下,解压命名为waf。

2、在nginx.conf的http段添加

lua_package_path "/usr/local/nginx/conf/waf/?.lua";
lua_shared_dict limit 10m;
init_by_lua_file  /usr/local/nginx/conf/waf/init.lua;
access_by_lua_file /usr/local/nginx/conf/waf/waf.lua;

配置config.lua里的waf规则目录(一般在waf/conf/目录下),绝对路径如有变动,需对应修改:

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

然后重启nginx即可

service nginx restart

配置

1、配置文件详细说明

    RulePath = "/usr/local/nginx/conf/waf/wafconf/"
    --规则存放目录
    attacklog = "on"n
    --是否开启攻击信息记录,需要配置logdir
    logdir = "/home/wwwlogs/"
    --log存储目录,需要nginx用户的可写权限。该目录LNMP默认建立,放在这个目录即可
    --日志文件名称格式如下:虚拟主机名_sec.log
    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~~]]
    --警告内容,可在中括号内自定义
    备注:不要乱动双引号,区分大小写

2、部署完毕可以尝试如下命令进行测试:

curl https://www.youfencun.com/index.php?id=../etc/passwd

返回网站防火墙Html源码即表示配置成功,也可通过网页访问,返回如下图所示:

未分类

在Ghost博客的nginx服务器上部署防盗链

折腾了一晚上,终于搞定了。搜索了很久都没有搜到有相关的中文文章,甚至英文的都很少,全是generic的nginx部署防盗链的文章,特此总结整理一下方便以后查询。

想必nginx防盗链的部署方法大家都知道了,在装了Ghost的情况下稍稍有所不同,主要因为实际访问的文件不在根目录下,而是在ghost的安装目录中,所以要用到proxy。就因为这一点折腾了好久,症状就是加入防盗链代码后所有图片自动404,加了proxy之后就好了。

以下是我使用的代码:

location /content/ {
  valid_referers none blocked ~.google. ~.bing. ~.baidu. server_names ~($host);
  if ($invalid_referer) {
    rewrite ^/ http://ww1.sinaimg.cn/large/76b129b3gy1fisvu3x79lj21hc0u0ta2.jpg;
     }
   try_files $uri @ghost;
}


location @ghost {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://127.0.0.1:2368;
}

代码解释如下:

location /content/

↑因为ghost的特殊性,所有上传的图片都在content目录下,如有需求还是改成扫描文件后缀。

valid_referers none blocked ~.google. ~.bing. ~.baidu. server_names ~($host);

↑关于valid_referers网上的解释很多了,推荐阅读 官网的定义(https://nginx.org/en/docs/http/ngx_http_referer_module.html) 。包含了几个搜索引擎,当然不希望图片被搜索引擎爬的也可以去掉,后面使用了host变量方便大家直接复制黏贴。

if ($invalid_referer) 

↑当来源没有列在上述列表中,$invalid_refererfan返回值为1,执行rewrite。

rewrite ^/ http://ww1.sinaimg.cn/large/76b129b3gy1fisvu3x79lj21hc0u0ta2.jpg;

↑rewrite到一个外部图床的防盗链图片,注意用自己的图片网址替换我的网址,如果不需要,可直接 return 444。

try_files $uri @ghost;

↑最重要的一步,因为实际访问的文件并不在服务器的root directory下,本身ghost-cli自动部署的nginx配置就带proxy。try_files的定义请看官方文档。

location @ghost {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://127.0.0.1:2368;
}

↑这里我照抄了ghost-cli部署时写入的proxy代码。

写入conf之后重启nginx即可。

注:由于本站强制https访问,所以在http段直接设置了所有访问content都rewrite到盗链图片上:

location /content/ {
    rewrite ^/ http://ww1.sinaimg.cn/large/76b129b3gy1fisvu3x79lj21hc0u0ta2.jpg;
}

Nginx反向代理缓存引发的跨域问题

一、前言

贵金属wap版直播间上线后,偶尔有用户反馈,在进入wap直播间的时候,出现空白页面,但是重新刷新又可以正常显示了。我们曾一度认为是网络请求异常或兼容问题,直到开发PC版直播间,在进行调试中,同样遇到了“白屏”问题,才引起了足够重视,并进行了问题跟踪与分析。现在跟大家分享一下,这种偶然现象出现的原因。

我们的直播间落地页在fa.163.com 系统,而直播间内容,是通过 向直播间系统 qz.fa.163.com 发起Ajax请求获取的。在出现“白屏”的时候,可以通过浏览器的调试窗口,可以看到出现下面的报错:

未分类

二、问题分析

从上述错误提示文案中可以看到,问题首先和 跨域 有关。

何为跨域

从字面上理解为“跨域名”,
浏览器不能执行其他网站的脚本,然而,跨域不仅仅局限于域名这一项。只要协议、域名、端口有任何一个不同,都被当作是不同的域。 这是由于>同源策略的限制,从一个域上加载的脚本不允许访问另外一个域的文档属性。虽然在浏览器中,<script>、<img>、<iframe>、<link>等标签都>可>以加载跨域资源,而不受同源限制,但浏览器会限制脚本中发起的跨域请求。比如,使用 XMLHttpRequest 对象和Fetch发起 HTTP 请求就必须遵守同源策略。

同源策略/SOP(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。SOP要求两个通讯地址的协议、域名、端口号必须相同,否则两个地址的通讯将被浏览器视为不安全的,并被block下来。

举个例子:从贵金属主站 http://fa.163.com 发起请求访问以下url:

未分类

解决跨域

在实际应用中有多种方式来解决跨域问题,相信在实践中都会用到其中的某些方案:

1、JSONP (无状态连接,不能获悉连接状态和错误事件,而且只能走GET的形式)

2、iframe形式

3、服务器代理

页面直接向同域的服务端发请求,服务端进行跨域处理或爬虫后,再把数据返回给客户端页。

4、CORS

CORS(Cross-Origin Resource Sharing)跨域资源共享,定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通。CORS背后的基本思想就>是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。目前,所有浏览器都支持该功能,IE浏览器不能低>于IE10。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏>览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

CORS方式实现:

浏览器在发出CORS请求时会在头信息之中增加一个Origin字段;

后端返回代码中增加三个字段

header(“Access-Control-Allow-Origin”:“”);           // 必选 允许所有来源访问
header(“Access-Control-Allow-Credentials”:“true”);  //可选 是否允许发送cookie
header(“Access-Control-Allow-Method”:“POST,GET”);   //可选 允许访问的方式

5、nginx反向代理

nginx是一个高性能的web服务器,常用作反向代理服务器。nginx作为反向代理服务器,就是把http请求转发到另一个或者一些服务器上。通过把本地一个url前缀映射到要跨域访问的web服务器上,就可以。

为了解决跨域问题,我们选择方案d , 在直播间的过滤器中,统一添加了如下代码:

   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    // 加入响应头
    String origin = request.getHeader("Origin");
    if("http://fa.163.com".equals(origin) || "https://fa.163.com".equals(origin) ) {
        response.addHeader("Access-Control-Allow-Origin", origin);
        response.addHeader("Access-Control-Allow-Credentials", "true");
    }
    return true;
}

从错误提示文案中,我们还可以看到错误提示的关键点 “http://fa.163.com” that is not equal to the supplied origin. Origin ‘https://fa.163.com‘ is therefore not allowed access.
目前我们的系统同时支持http访问和https访问,但是为什么使用 http访问 ,返回的header中却是 https 协议呢?

通过多次模拟,确认出现问题的请求中,Request URL使用的协议和 response返回的headers中的 Access-Control-Allow-Origin 中的 协议确实不一致,且还有一个特性,X-Cached 为 HIT,如下图:

未分类

命中了缓存的请求,出现了协议不一致?

突然想到,这个接口,我们配置了nginx 缓存,那必然和nginx缓存有关了。

Nginx 缓存

Nginx (engine x) 是一个高性能的HTTP和反向代理服务器。
首先从源服务器(内部网络上的web服务器)上获取内容,然后把内容返回给用户,同时,也会把内容保存到代理服务器上一份,这样日后再接收同样的信息请求时,他会把本地缓存里的内容直接发给用户,以此减少后端web服务器的压力,提高响应速度。这其实就是缓存服务器所实现的功能。如下图所示。

未分类

进入直播间后,首先需要查询直播内容是否有更新,而这个接口客户端会以5s间隔轮询,为了减少tomcat的压力,我们配置了nginx缓存。配置如下:

未分类

其中:

  • proxy_cache_methods: 用来设置HTTP哪些方法会被缓存,直播间接口配置了GET、HEAD、POST;
  • proxy_cache_valid: 用来设置对不同HTTP状态码的不同缓存时间。直播间接口配置了对于 返回值为200的状态码,缓存5秒;
  • proxy_cache_min_uses: 用来设置多少次访问后,应答值会被缓存,配置为3次;
  • proxy_cache_key: 设置Web缓存的key
  • proxy_cache: 用来设置哪个缓存区将被使用,并定义缓存区的名称

通过上述配置,我们可以看到 proxy_cache_key 配置中,只配置了host + uri + 参数,但没有配置协议,所以无论用http访问,还是https访问,只要被缓存后,返回的内容都是一样的,而不会区分http或https。从而引起了跨域问题。

至此,问题分析完毕。

三、问题解决

跟运维同学沟通后,通过修改nginx配置,将协议类型scheme加入到缓存查找的判断参数中,配置如下。

未分类

问题得到了解决。

四 、总结

上述“惨案” ,是 跨域、nginx缓存、http/https协议 这三种条件同时出现引发的。

如果不涉及跨域,混用 http/https协议 + nginx缓存,其实也是没有问题的。但是一旦出现了跨域使用,必须 在nginx 缓存配置中,配置 scheme + host + uri + 参数。

nginx日志切割shell脚本

一、脚本思路

第一步就是重命名日志文件,不用担心重命名后nginx找不到日志文件而丢失日志。在你未重新打开原名字的日志文件前,nginx还是会向你重命名的文件写日志,linux是靠文件描述符而不是文件名定位文件。

第二步向nginx主进程发送USR1信号。

nginx主进程接到信号后会从配置文件中读取日志文件名称,重新打开日志文件(以配置文件中的日志名称命名),并以工作进程的用户作为日志文件的所有者。

重新打开日志文件后,nginx主进程会关闭重名的日志文件并通知工作进程使用新打开的日志文件。

工作进程立刻打开新的日志文件并关闭重名名的日志文件。

然后你就可以处理旧的日志文件了。

二、脚本实现

nginx日志按日期自动切割脚本如下:

#nginx日志切割脚本

#!/bin/bash
#设置日志文件存放目录
logs_path="/usr/local/nginx/logs/"
#设置pid文件
pid_path="/usr/local/nginx/nginx.pid"

#重命名日志文件
mv ${logs_path}access.log ${logs_path}access_$(date -d "yesterday" +"%Y%m%d").log

#向nginx主进程发信号重新打开日志
kill -USR1 `cat ${pid_path}`

试验环境:

# cat /etc/redhat-release 
Red Hat Enterprise Linux Server release 5.3 (Tikanga)

# /opt/nginx/nginx -v
nginx version: nginx/1.6.2

代码:

#!/bin/bash
# ==============================================================================
# chmod u+x /opt/nginx/cut_nginx_log.sh
# crontab -e
# 0 0 * * * /opt/nginx/cut_nginx_log.sh > /opt/nginx/logs/cut_nginx_log.log 2>&1
# ==============================================================================

LOGS_PATH="/opt/nginx/logs"
ARCHIVE_YEAR=$(date -d "yesterday" "+%Y")
ARCHIVE_MONTH=$(date -d "yesterday" "+%m")
ARCHIVE_DATE=$(date -d "yesterday" "+%Y%m%d_%H%M%S")
if [ -r /opt/nginx/nginx.pid ]; then
  mkdir -p "${LOGS_PATH}/${ARCHIVE_YEAR}/${ARCHIVE_MONTH}"
  mv "${LOGS_PATH}/access.log" "${LOGS_PATH}/${ARCHIVE_YEAR}/${ARCHIVE_MONTH}/access_${ARCHIVE_DATE}.log"
  kill -USR1 $(cat "/opt/nginx/nginx.pid")
  sleep 1
  gzip "${LOGS_PATH}/${ARCHIVE_YEAR}/${ARCHIVE_MONTH}/access_${ARCHIVE_DATE}.log"
else
  echo "Nginx might be down"
fi

# ==============================================================================
# Clean up log files older than 100 days
# ==============================================================================

# Change HOUSEKEEPING=1 to enable clean up
HOUSEKEEPING=0
KEEP_DAYS=100
if [ $HOUSEKEEPING == 1 ]; then
  if [ -d "${LOGS_PATH}" ]; then
    find "${LOGS_PATH}" -type f -name "access_*.log.gz" -mtime +${KEEP_DAYS} -exec rm -f {} ;
  fi
fi

参考:
http://wiki.nginx.org/LogRotation

保存以上脚本nginx_log.sh,并设置定时切割任务

三、定时工作

在crontab中设置作业

0 0 * * * bash /usr/local/nginx/nginx_log.sh

这样就每天的0点0分把nginx日志重命名为日期格式,并重新生成今天的新日志文件。