防盗链,通俗讲,就是不让别人盗用网站上的资源,这个资源通常是指图片、视频、歌曲、文档等。
防止有人利用网站文件上传的功能,把一些静态媒体资源放到我们的网站上,然后在他们的网站上设置这些资源的链接到我们的网站上,当他们网站用户访问这些资源时,就会跳转到我们的服务器上,导致我们的服务器带宽流量异常增大。为了防止这种情况发生,我们利用apache服务器访问控制实现防盗链功能。
# vim /usr/local/apache2.4/conf/extra/httpd-vhosts.conf
<VirtualHost *:80>
ServerAdmin [email protected]
DocumentRoot "/data/wwwroot/123.com"
ServerName 123.com
ServerAlias www.123.com
CustomLog "|/usr/local/apache2.4/bin/rotatelogs -l logs/123.com-access_%Y%m%d.log 86400" combined
<Directory /data/wwwroot/123.com>
SetEnvIfNoCase Referer "http://www.123.com" local_ref #指定referer白名单
SetEnvIfNoCase Referer "http://123.com" local_ref #指定referer白名单
SetEnvIfNoCase Referer "^$" local_ref #空的referer也能访问
<FilesMatch "\.(txt|doc|mp3|zip|rar|jpg|gif)"> #定义保护文件类型
Order Allow,Deny #访问控制顺序,先允许后拒绝。
Allow from env=local_ref #只有符合白名单上的referer才能访问123.com目录。
</FilesMatch>
</Directory>
referer
指的是访问该网站时上一次访问某个网站的网址,^$
表示空referer
,当直接在浏览器输入图片地址去访问它时,它的referer
就为空。
# curl -x127.0.0.1:80 -I -e "http://www.123.com/123.txt" http://www.123.com/1.jpg # -e 定义referer,这个referer一定要以http://开头,否则不管用
HTTP/1.1 403 Forbidden
Date: Sun, 01 Jul 2018 01:24:44 GMT
Server: Apache/2.4.33 (Unix) PHP/5.6.36
X-Powered-By: PHP/5.6.36
Content-Type: text/html; charset=UTF-8
可以看到,使用非允许的referer会返回403的状态码。
# curl -x127.0.0.1:80 -I -e "http://www.123.com/123.txt" http://www.123.com/index.html
HTTP/1.1 200 OK
Date: Sun, 01 Jul 2018 01:26:20 GMT
Etag:"8-53ceaf03230b4"
Accept-Ranges:bytes
Content-Length:8
Content-Type:text/html
访问html类型的文件时,返回200,说明不会被禁止。
对于比较重要的网站内容,除了可以使用用户认证限制访问之外,还可以限制IP
和限制user_agent
,限制IP指的是限制访问网站的来源IP,而限制user_agent,通常用来限制恶意或者不正常的请求。
# vim /usr/local/apache2.4/conf/extra/httpd-vhosts.conf
<VirtualHost *:80>
ServerAdmin [email protected]
DocumentRoot "/data/wwwroot/123.com"
ServerName 123.com
ServerAlias www.123.com
CustomLog "|/usr/local/apache2.4/bin/rotatelogs -l logs/123.com-access_%Y%m%d.log 86400"
combined
<Directory /data/wwwroot/123.com/admin/> #指定要限制访问的目录
Order deny,allow #order定义控制顺序,哪个在前就先匹配哪个规则
Deny from all #所有的来源IP都被限制
Allow from 127.0.0.1 #允许来源为127.0.0.1的访问
</Directory>
ErrorLog "logs/123.com-error_log"
CustomLog "logs/123.com-access_log" common
</VirtualHost>
# mkdir /data/wwwroot/123.com/admin/ #创建admin目录,模拟后台
# echo "admin" > /data/wwwroot/123.com/admin/index.html #在后台目录创建文件,并写入内容
# > /usr/local/apache2.4/logs/123.com-access_20180701.log #清空当天的访问日志
# /usr/local/apache2.4/bin/apachectl -t
Syntax OK
# /usr/local/apache2.4/bin/apachectl graceful
# curl -x192.168.100.140:80 -I 123.com/admin/index.html
HTTP/1.1 403 Forbidden #IP为192.168.100.140的访问被禁止
Date: Sun, 01 Jul 2018 03:28:28 GMT
Server: Apache/2.4.33 (Unix) PHP/5.6.36
Content-Type: text/html; charset=iso-8859-1
# curl -x127.0.0.1:80 -I 123.com/admin/index.html
HTTP/1.1 200 OK #IP为127.0.0.1的访问被允许
Date: Sun, 01 Jul 2018 03:31:47 GMT
Server: Apache/2.4.33 (Unix) PHP/5.6.36
Last-Modified: Sun, 01 Jul 2018 03:13:45 GMT
ETag: "6-56fe7780401e4"
Accept-Ranges: bytes
Content-Length: 6
Content-Type: text/html
# tail -1 /usr/local/apache2.4/logs/123.com-access_20180701.log
192.168.100.1 - - [01/Jul/2018:11:32:58 +0800] "GET /admin/ HTTP/1.1" 403 215 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.5514.400 QQBrowser/10.1.1660.400" #可以看到Windows机器上的访问记录,我这里是QQ浏览器
用Windows机器在浏览器上访问:
显示Forbidden,无法访问到123.com/admin/
目录。
# vim /usr/local/apache2.4/conf/extra/httpd-vhosts.conf
<VirtualHost *:80>
ServerAdmin [email protected]
DocumentRoot "/data/wwwroot/123.com"
ServerName 123.com
ServerAlias www.123.com
CustomLog "|/usr/local/apache2.4/bin/rotatelogs -l logs/123.com-access_%Y%m%d.log 86400" combined
<Directory /data/wwwroot/123.com>
<FilesMatch "admin.php(.*)"> #指定要限制访问的文件
Order deny,allow #order定义控制顺序,哪个在前就先匹配哪个规则
Deny from all #所有的来源IP都被限制
Allow from 127.0.0.1 #允许来源为127.0.0.1的访问
</FilesMatch>
</Directory>
ErrorLog "logs/123.com-error_log"
CustomLog "logs/123.com-access_log" common
</VirtualHost>
# /usr/local/apache2.4/bin/apachectl -t
Syntax OK
# /usr/local/apache2.4/bin/apachectl graceful
# curl -x192.168.100.140:80 -I '123.com/admin.php?asadfwepf'
HTTP/1.1 403 Forbidden #IP为192.168.100.140的访问被禁止
Date: Sun, 01 Jul 2018 03:58:00 GMT
Server: Apache/2.4.33 (Unix) PHP/5.6.36
Content-Type: text/html; charset=iso-8859-1
# curl -x127.0.0.1:80 -I '123.com/admin.php?asadfwepf'
HTTP/1.1 404 Not Found #IP为127.0.0.1的访问被允许,404表示已经可以访问,但找不到对应的文件,因为这里我并没有去创建这个文件
Date: Sun, 01 Jul 2018 03:58:35 GMT
Server: Apache/2.4.33 (Unix) PHP/5.6.36
Content-Type: text/html; charset=iso-8859-1
除了可以对目录和文件做访问控制外,我们还可以把能上传文件的目录禁止解析PHP代码,对于使用PHP语言编写的网站,这样做无疑更加安全。
# vim /usr/local/apache2.4/conf/extra/httpd-vhosts.conf
<VirtualHost *:80>
ServerAdmin [email protected]
DocumentRoot "/data/wwwroot/123.com"
ServerName 123.com
ServerAlias www.123.com
CustomLog "|/usr/local/apache2.4/bin/rotatelogs -l logs/123.com-access_%Y%m%d.log 86400" combined
<Directory /data/wwwroot/123.com/upload>
php_admin_flag engine off
#
# Order deny,allow
# Deny from all
# Allow from 127.0.0.1
#
</Directory>
ErrorLog "logs/123.com-error_log"
CustomLog "logs/123.com-access_log" common
</VirtualHost>
# /usr/local/apache2.4/bin/apachectl -t
Syntax OK
# /usr/local/apache2.4/bin/apachectl graceful
# mkdir /data/wwwroot/123.com/upload
# cp /usr/local/apache2.4/htdocs/1.php /data/wwwroot/123.com/upload/
# curl -x127.0.0.1:80 123.com/upload/1.php
<?php
echo "php解析正常"; #这里显示的是代码,说明1.php无法正常解析
?>
user_agent
就是指浏览器标识,当用curl访问时,user_agent为“curl/7.29.0”,针对user_agent可以限制一些访问,例如蜘蛛爬虫或cc攻击,这一类的恶意请求的user_agent相同或者类似,这样我们就可以限制user
_agent发挥防攻击的作用。
# vim /usr/local/apache2.4/conf/extra/httpd-vhosts.conf
<VirtualHost *:80>
ServerAdmin [email protected]
DocumentRoot "/data/wwwroot/123.com"
ServerName 123.com
ServerAlias www.123.com
CustomLog "|/usr/local/apache2.4/bin/rotatelogs -l logs/123.com-access_%Y%m%d.log 86400" combined
<IfModule mod_rewrite.c> #用到rewrite模块
RewriteEngine on #打开rewrite模块功能
RewriteCond %{HTTP_USER_AGENT} .*curl.* [NC,OR] # %{HTTP_USER_AGENT}为user_agent的内置变量 ,NC表示不区分大小写,OR表示或
RewriteCond %{HTTP_USER_AGENT} .*baidu.com.* [NC] #匹配了curl和baidu.com
RewriteRule .* - [F] #指定规则,F表示Forbidden
</IfModule>
#
# php_admin_flag engine off
#
# Order deny,allow
# Deny from all
# Allow from 127.0.0.1
#
#
ErrorLog "logs/123.com-error_log"
CustomLog "logs/123.com-access_log" common
</VirtualHost>
# /usr/local/apache2.4/bin/apachectl -t
Syntax OK
# /usr/local/apache2.4/bin/apachectl graceful
# curl -x127.0.0.1:80 -I 123.com/upload/1.php
HTTP/1.1 403 Forbidden #curl的user_agent被禁止
Date: Sun, 01 Jul 2018 04:33:24 GMT
Server: Apache/2.4.33 (Unix) PHP/5.6.36
Content-Type: text/html; charset=iso-8859-1
# curl -A "123" -x127.0.0.1:80 -I 123.com/upload/1.php # -A 指定user_agent
HTTP/1.1 200 OK #指定user_agent为123之后,访问成功
Date: Sun, 01 Jul 2018 04:34:48 GMT
Server: Apache/2.4.33 (Unix) PHP/5.6.36
X-Powered-By: PHP/5.6.36
Content-Type: text/html; charset=UTF-8
PHP虽然是作为httpd的一个模块的形式存在的,但PHP也有自己的配置文件。
# /usr/local/php/bin/php -i |grep -i "loaded configuration file"
PHP Warning: Unknown: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in Unknown on line 0
Loaded Configuration File => /usr/local/php/etc/php.ini
PHP.ini
为PHP的配置文件,可以看出它在/usr/local/php/etc/php.ini
,第一行是警告信息,可以取消。
# vim /usr/local/php/etc/php.ini
date.timezone = Asia/Shanghai #找到data.timezone(设置时区参数),设置为上海
# /usr/local/php/bin/php -i |grep -i "loaded configuration file"
Loaded Configuration File => /usr/local/php/etc/php.ini
disable_functions
PHP有很多内置的函数,有一些函数(如exec)会直接调用Linux系统命令,开放的话会比较危险,因此基于安全考虑要禁掉。
# vim /usr/local/php/etc/php.ini
disable_functions = eval,assert,popen,passthru,escapeshellarg,escapeshellcmd,passthru,exec,system,chroot,scandir,chgrp,chown,escapeshellcmd,escapeshellarg,shell_exec,proc_get_status,ini_alter,ini_restore,dl,pfsockopen,openlog,syslog,readlink,symlink,leak,popepassthru,stream_socket_server,popen,proc_open,proc_close
# /usr/local/apache2.4/bin/apachectl restart
PHP的日志对于程序员来讲非常重要,是排错的重要手段。
# vim /usr/local/php/etc/php.ini
log_errors = On #搜索log_errors ,改为 on
error_log = /var/log/php/php_errors.log #搜索error_log 改为/var/log/php/php_errors.log
error_reporting = E_ALL & ~E_NOTICE #搜索error_reporting,改为E_ALL & ~E_NOTICE
display_errors = Off #搜索display_errors,改为off
logs_errors 可以设置为on或off,如果想让PHP记录错误日志,就设置为on
error_log 设定错误日志路径
error_reporting 设定错误日志的基本,E_ALL为所有类型的日志,不管是提醒还是警告都会记录,&表示并且,~表示排除,即在E_ALL的基础上排除notice相关的日志
display_errors 设置为on,则会把错误日志直接显示在浏览器里,这对用户来说体验不好,还会暴露网站相关信息,因此设置为off
# mkdir /var/log/php
# chmod 777 /var/log/php #需要保证PHP的错误日志所在目录存在,且权限为可写
# /usr/local/apache2.4/bin/apachectl graceful
# vim /data/wwwroot/123.com/3.php
<?php
echo lzx
# curl -A "123" -x127.0.0.1:80 -I 123.com/3.php
HTTP/1.0 500 Internal Server Error #说明访问的页面存在错误
Date: Sun, 01 Jul 2018 05:35:42 GMT
Server: Apache/2.4.33 (Unix) PHP/5.6.36
X-Powered-By: PHP/5.6.36
Connection: close
Content-Type: text/html; charset=UTF-8
# cat /var/log/php/php_errors.log
[01-Jul-2018 13:35:42 Asia/Shanghai] PHP Parse error: syntax error, unexpected end of file, expecting ',' or ';' in /data/wwwroot/123.com/3.php on line 4
通过日志可以判断,3.php文件第四行少了个分号。
# vim /data/wwwroot/123.com/3.php
<?php
echo lzx; #给3.php增加分号
# curl -A "123" -x127.0.0.1:80 -I 123.com/3.php
HTTP/1.1 200 OK #访问成功
Date: Sun, 01 Jul 2018 05:39:59 GMT
Server: Apache/2.4.33 (Unix) PHP/5.6.36
X-Powered-By: PHP/5.6.36
Content-Type: text/html; charset=UTF-8
open_basedir
一个服务器上可以跑很多个网站,但是这样做会有一些弊端,因为如果一个网站被黑,那很有可能波及到很多站点。
不过PHP有open_basedir,它的作用是将网站限定在指定目录里,就算某站点被黑,黑客也只能在该目录下活动,而不能左右其他目录。
# vim /usr/local/php/etc/php.ini
open_basedir = /tmp:/data/wwwroot/123.com #搜索 open_basedir,改成/tmp:/data/wwwroot/123.com
open_basedir可以是多个目录,用:
分隔,上面已经限制PHP只能在/tmp和/data/wwwroot/123.com两个目录下面里面活动。
# /usr/local/apache2.4/bin/apachectl graceful
# cp /usr/local/apache2.4/htdocs/1.php /data/wwwroot/abc.com/
# curl -A "123" -x127.0.0.1:80 -I abc.com/1.php
HTTP/1.0 500 Internal Server Error
Date: Sun, 01 Jul 2018 05:56:56 GMT
Server: Apache/2.4.33 (Unix) PHP/5.6.36
X-Powered-By: PHP/5.6.36
Connection: close
Content-Type: text/html; charset=UTF-8
发现abc.com/1.php
不能访问,状态码为500。
[01-Jul-2018 13:56:56 Asia/Shanghai] PHP Warning: Unknown: open_basedir restriction in effect. File(/data/wwwroot/abc.com/1.php) is not within the allowed path(s): (/tmp:/data/wwwroot/123.com) in Unknown on line 0
[01-Jul-2018 13:56:56 Asia/Shanghai] PHP Warning: Unknown: failed to open stream: Operation not permitted in Unknown on line 0
[01-Jul-2018 13:56:56 Asia/Shanghai] PHP Fatal error: Unknown: Failed opening required '/data/wwwroot/abc.com/1.php' (include_path='.:/usr/local/php/lib/php') in Unknown on line 0
上面表明限制成功。
我们还可以给单个虚拟主机配置open_basedir。
对于php.ini里面的配置,在httpd.conf也是可以设置的:
# vim /usr/local/apache2.4/conf/extra/httpd-vhosts.conf
<VirtualHost *:80>
ServerAdmin [email protected]
DocumentRoot "/data/wwwroot/123.com"
ServerName 123.com
ServerAlias www.123.com
CustomLog "|/usr/local/apache2.4/bin/rotatelogs -l logs/123.com-access_%Y%m%d.log 86400" combined
php_admin_value open_basedir "/data/wwwroot/123.com/:/tmp/" # php_admin_value 可以定义php.ini里面的参数
#
# RewriteEngine on
# RewriteCond %{HTTP_USER_AGENT} .*curl.* [NC,OR]
# RewriteCond %{HTTP_USER_AGENT} .*baidu.com.* [NC]
# RewriteRule .* - [F]
#
#
# php_admin_flag engine off
#
# Order deny,allow
# Deny from all
# Allow from 127.0.0.1
#
#
ErrorLog "logs/123.com-error_log"
CustomLog "logs/123.com-access_log" common
</VirtualHost>
起作用的是php_admin_value
,除此之外的像error_log之类的也可以定义,这样就可以实现,一个虚拟主机定义一个open_basedir。
编译httpd时,有涉及到动态和静态模块,其实PHP也有。在之前PHP安装时,所有的模块全部为静态模块,没有动态模块。所谓动态,就是一个单独存在的.so
文件,在httpd中PHP就是以动态模块的形式被加载的。
PHP一旦编译完成后,想要再增加一个功能模块的话,要么重新编译,要么直接编译一个扩展模块(生成一个.so
文件),然后在php.ini中配置一下。
# /usr/local/php/bin/php -m
[PHP Modules]
bz2
Core
ctype
date
dom
ereg
exif
fileinfo
filter
gd
hash
iconv
json
libxml
mbstring
mcrypt
mysql
mysqli
openssl
pcre
PDO
pdo_mysql
pdo_sqlite
Phar
posix
Reflection
session
SimpleXML
soap
sockets
SPL
sqlite3
standard
tokenizer
xml
xmlreader
xmlwriter
zlib
[Zend Modules]
# cd /usr/local/src/
# wget https://codeload.github.com/phpredis/phpredis/zip/develop
# mv develop phpredis-develop.zip #改名为phpredis-develop.zip
# unzip phpredis-develop.zip #解压phpredis-develop.zip
# cd phpredis-develop
# /usr/local/php/bin/phpize #目的是生成configure文件
Configuring for:
PHP Api Version: 20131106
Zend Module Api No: 20131226
Zend Extension Api No: 220131226
Cannot find autoconf. Please check your autoconf installation and the
$PHP_AUTOCONF environment variable. Then, rerun this script. #提示错误Cannot find autoconf,需要安装autoconf
# yum install -y autoconf
# /usr/local/php/bin/phpize
Configuring for:
PHP Api Version: 20131106
Zend Module Api No: 20131226
Zend Extension Api No: 220131226
# ./configure --with-php-config=/usr/local/php/bin/php-config
# echo $?
0
# make
# echo $?
0
# make install
Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-zts-20131226/ #make install 的时候会把编译好的redis.so文件放到扩展模块存放目录下面
# echo $?
0
# /usr/local/php/bin/php -i | grep extension_dir #查看扩展模块存放目录,可以在php.ini中自定义该路径
extension_dir => /usr/local/php/lib/php/extensions/no-debug-zts-20131226 => /usr/local/php/lib/php/extensions/no-debug-zts-20131226
sqlite3.extension_dir => no value => no value
# ls /usr/local/php/lib/php/extensions/no-debug-zts-20131226
opcache.so redis.so #可以看到 redis.so
# vim /usr/local/php/etc/php.ini
extension = redis.so #增加这一行配置
# /usr/local/php/bin/php -m | grep redis #查看是否加载redis模块
redis #可以看到已经加载redis模块
# /usr/local/apache2.4/bin/apachectl restart #想要使用redis模块,需要重启httpd服务
更多资料参考:
Apache Rewrite规则详解
php.ini详解