LNMP环境搭建+Nginx/MySQL/PHP加固+安全思考

该LNMP环境是在windows的VMware Workstation Pro中的Centos虚拟机上搭建的,各个软件的版本为:Centos7 + Nginx1.12.2 + Mysql-5.6.38 + PHP7.2.0。

0x01 前置知识

Linux 从入门到精通

ps

linux上进程有5种状态:

1.运行(正在运行或在运行队列中等待)

2.中断(休眠中, 受阻, 在等待某个条件的形成或接受到信号)

3.不可中断(收到信号不唤醒和不可运行, 进程必须等待直到有中断发生)

4.僵死(进程已终止, 但进程描述符存在, 直到父进程调用wait4()系统调用后释放)

5.停止(进程收到SIGSTOP, SIGSTP, SIGTIN, SIGTOU信号后停止运行运行)

ls

使用带"-l"选项的ls命令时,将以长格式显示文件或目录的详细信息,其中包括了该文件的权限和归属等参数。例如,执行如下操作列出当前目录下子目录和文件的详细属性。
在这里插入图片描述
第1个字符:表示该文件的类型,可以是d(目录)、b(块设备)、c(字符设备文件)、-(普通文件)、l(链接文件)等。

第2~4个字符:表示该文件的属主用户(user)对该文件的访问权限。

第5~7个字符:表示该文件的属组内各成员用户对该文件的访问权限。

第8~10个字符:表示其他任何用户(Other)对该文件的访问权限。

“r、w、x"分别表示可读、可写、可执行。若需要去除对应的权限,则使用”-"表示。
在这里插入图片描述
whereis

whereis命令只能用于程序名的搜索,而且只搜索二进制文件(参数-b)、man说明文件(参数-m)和源代码文件(参数-s)。如果省略参数,则返回所有信息。

和find相比,whereis查找的速度非常快,这是因为linux系统会将系统内的所有文件都记录在一个数据库文件中,当使用whereis和下面即将介绍的locate时,会从数据库中查找数据,而不是像find命令那样,通 过遍历硬盘来查找,效率自然会很高。

但是该数据库文件并不是实时更新,默认情况下时一星期更新一次,因此,我们在用whereis和locate 查找文件时,有时会找到已经被删除的数据,或者刚刚建立文件,却无法查找到,原因就是因为数据库文件没有被更新。

nginx user模块

Nginx 主进程(master process)会以 root 权限运行,之后主进程会读取 /etc/nginx/nginx.conf 文件中的 user 模块的配置,nginx 会使用配置指定的用户启动工作进程( worker process)。

那为什么主进程需要使用 root 权限?因为只有 root 可以监听小于1024的端口号,通常 webserver 使用 80/443 端口,这也就是为什么需要 root 来运行了。如果要更改非 root 用户来运行,需要更改下面的文件用户和用户组,当然你也就不能使用 <1024 的端口了。

nginx中的location指令

  • 精确匹配 location =(完全一致)
  • 前缀匹配 location ^~(匹配上以后不再进行后续的正则搜索)
  • 正则匹配 location ~(区分大小写)location ~*(不区分大小写)
  • 匹配不带任何修饰的前缀匹配location /

Linux shell

Linux中的shell,是指一个面向用户的命令接口,表现形式就是一个可以由用户录入的界面,这个界面也可以反馈运行信息。

Linux 工作目录与主目录

从逻辑上讲,用户在登录到Linux系统中之后,每时每刻都处在某个目录之中,此目录被称做工作目录或当前目录(Working Directory)。工作目录是可以随时改变的。用户初始登录到系统中时,其主目录(HomeDirectory)就成为其工作目录。

MySQL配置文件中basedir和datadir说明

1、basedir参数
原文说明为:Path to installation directory. All paths are usually resolved relative to this.
解释:该参数指定了安装 MySQL 的安装路径(mysql安装目录),填写全路径可以解决相对路径所造成的问题。

2、datadir 参数
原文说明为:Path to the database root.
解释:该参数指定MySQL的数据文件的存放目录,数据库文件即我们常说的 MySQL data 文件。

不安全的php函数

  • phpinfo() 功能描述:输出 PHP 环境信息以及相关的模块、WEB 环境等信息。危险等级:中
  • passthru() 功能描述:允许执行一个外部程序并回显输出,类似于 exec()。危险等级:高
  • exec() 功能描述:允许执行一个外部程序(如 UNIX Shell 或 CMD 命令等)。危险等级:高
  • system() 功能描述:允许执行一个外部程序并回显输出,类似于 passthru()。危险等级:高
  • chroot() 功能描述:可改变当前 PHP 进程的工作根目录,仅当系统支持 CLI 模式 PHP 时才能工作,且该函数不适用于 Windows 系统。危险等级:高
  • scandir() 功能描述:列出指定路径中的文件和目录。危险等级:中
  • chgrp() 功能描述:改变文件或目录所属的用户组。危险等级:高
  • chown() 功能描述:改变文件或目录的所有者。危险等级:高
  • shell_exec() 功能描述:通过 shell 执行命令,并将执行结果作为字符串返回。危险等级:高
  • proc_open() 功能描述:执行一个命令并打开文件指针用于读取以及写入。危险等级:高
  • proc_get_status() 功能描述:获取使用 proc_open() 所打开进程的信息。危险等级:高
  • error_log() 功能描述:将错误信息发送到指定位置(文件)。安全备注:在某些版本的 PHP 中,可使用 error_log() 绕过 PHP safe mode, 执行任意命令。危险等级:低
  • ini_alter() 功能描述:是 ini_set() 函数的一个别名函数,功能与 ini_set() 相同。具体参见 ini_set()。危险等级:高
  • ini_set() 功能描述:可用于修改、设置 PHP 环境配置参数。危险等级:高
  • ini_restore() 功能描述:可用于恢复 PHP 环境配置参数到其初始值。危险等级:高
  • dl() 功能描述:在 PHP 进行运行过程当中(而非启动时)加载一个 PHP 外部模块。危险等级:高
  • pfsockopen() 功能描述:建立一个 Internet 或 UNIX 域的 socket 持久连接。危险等级:高
  • syslog() 功能描述:可调用 UNIX 系统的系统层 syslog() 函数。危险等级:中
  • readlink() 功能描述:返回符号连接指向的目标文件内容。危险等级:中
  • symlink() 功能描述:在 UNIX 系统中建立一个符号链接。危险等级:高
  • popen() 功能描述:可通过 popen() 的参数传递一条命令,并对 popen() 所打开的文件进行执行。危险等级:高
  • stream_socket_server() 功能描述:建立一个 Internet 或 UNIX 服务器连接。危险等级:中
  • putenv() 功能描述:用于在 PHP 运行时改变系统字符集环境。在低于 5.2.6 版本的 PHP 中,可利用该函数 修改系统字符集环境后,利用 sendmail 指令发送特殊参数执行系统 SHELL 命令。危险等级:高

0x02 安装虚拟机

官网下载Centos7对应的ios文件,在VMware上配置。配置完成后出现了localhost变成了bogon的问题,网上查询后得知是DNS反向解析出错导致。先使用ip add查询到虚拟机自动配置的ip,再使用vi /etc/hosts将 ip localhost 写入本地hosts文件,重启后问题解决。

1.更新系统软件:

yum update

2.查看是否已安装wget:

rpm -qa|grep wget

否则安装:

yum install wget

3.查看是否已安装编译器:

rpm -qa|grep gcc

否则安装:

yum install gcc gcc-c++

0x03 安装Nginx

1.安装nginx依赖包

nginx的Rewrite模块和HTTP核心模块会使用到PCRE正则表达式语法:

yum -y install pcre pcre-devel

nginx的各种模块中需要使用gzip压缩:

yum -y install zlib zlib-devel

安全套接字层密码库:

yum -y install openssl openssl-develv

2.下载nginx包并解压(到/usr/local/src目录中)

cd /usr/local/src

wget http://nginx.org/download/nginx-1.12.2.tar.gz

tar -zxvf nginx-1.12.2.tar.gz

3.编译安装(到/usr/local/nginx目录中)

cd nginx-1.12.2

./configure --prefix=/usr/local/nginx

make

make install

4.创建并设置nginx运行账号

groupadd nginx

useradd -M -g nginx -s /sbin/nologin nginx

cd /usr/local/nginx/conf

vim nginx.conf

设置user参数如下:

user nginx nginx

其他配置参数暂时无需改动。

5.设置nginx为系统服务

vim /lib/systemd/system/nginx.service

文件内容:

[Unit]

Description=nginx

After=network.target

[Service]

Type=forking

ExecStart=/usr/local/nginx/sbin/nginx

ExecReload=/usr/local/nginx/sbin/nginx -s reload

ExecStop=/usr/local/nginx/sbin/nginx -s stop

PrivateTmp=true

[Install]

WantedBy=multi-user.target

6.设置nginx开机自启动

systemctl enable nginx.service

7.开启nginx服务

systemctl start nginx.service

查看nginx是否启动成功:

ps aux | grep nginx

在虚拟机浏览器中访问测试:

http://localhost

8.防火墙开放80端口(nginx默认使用80端口,可在nginx.conf中配置,若无需进行远程访问则不需要开放端口)

永久开放80端口:

firewall-cmd --zone=public --add-port=80/tcp --permanent

重启防火墙:

firewall-cmd --reload

查看防火墙开启状态:

systemctl status firewalld

查看80端口是否开放成功:

firewall-cmd --zone=public --query-port=80/tcp

可在windows宿主主机浏览器直接访问虚拟机ip测试是否可以成功访问。

0x04 安装MySQL

1.卸载已有mysql

查看是否已安装mysql:

rpm -qa mysql

有则卸载:

rpm -e --nodeps 文件名称

是否存在与mysql相关的文件或目录:

whereis mysql

是则删除:

rm -rf 文件名称

rm -rf /usr/lib64/mysql

rm -rf /usr/share/mysql

存在/etc/my.cnf,则需要删除:

rm /etc/my.cnf

2.安装编译mysql需要的依赖包

yum install libevent* libtool* autoconf* libstd* ncurse* bison* openssl*

3.安装cmake(mysql5.5之后需要用cmake支持编译安装)

查看是否已安装cmake:

rpm -qa cmake

没有则下载编译安装:

cd /usr/local/src

wget http://www.cmake.org/files/v2.8/cmake-2.8.12.1.tar.gz

tar -zxvf cmake-2.8.12.1.tar.gz

cd cmake-2.8.12.1

./configure

make

make install

检查cmake是否安装成功:

cmaek --version

4.下载mysql包并解压(到/usr/local/src)

cd /usr/local/src

wget https://downloads.mysql.com/archives/get/p/23/file/mysql-5.6.38.tar.gz

tar -zxvf mysql-5.6.38.tar.gz

5.编译安装(到/usr/local/src/mysql-5.6.38)

cd mysql-5.6.38

cmake -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DMYSQL_DATADIR=/usr/local/mysql/data -DSYSCONFDIR=/etc -DWITH_MYISAM_STORAGE_ENGINE=1 -DWITH_INNOBASE_STORAGE_ENGINE=1 -DWITH_MEMORY_STORAGE_ENGINE=1 -DWITH_READLINE=1 -DMYSQL_UNIX_ADDR=/var/lib/mysql/mysql.sock -DMYSQL_TCP_PORT=3306 -DENABLED_LOCAL_INFILE=1 -DWITH_PARTITION_STORAGE_ENGINE=1 -DEXTRA_CHARSETS=all -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci

make

make install

6.配置mysql

groupadd mysql

useradd -M -g mysql -s /sbin/nologin mysql

chown -R mysql:mysql /usr/local/mysql

7.初始化配置

cd /usr/local/mysql/scripts

./mysql_install_db --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data

--user=mysql

8.设置mysql为系统服务

vi /lib/systemd/system/mysql.service

文件内容:

[Unit]

Description=mysql

After=network.target

[Service]

Type=forking

ExecStart=/usr/local/mysql/support-files/mysql.server start

ExecStop=/usr/local/mysql/support-files/mysql.server stop

ExecRestart=/usr/local/mysql/support-files/mysql.server restart

ExecReload=/usr/local/mysql/support-files/mysql.server reload

PrivateTmp=true

[Install]

WantedBy=multi-user.target

9.设置mysql服务开机自启动

systemctl enable mysql.service

10.启动mysql

systemctl start mysql.service

启动失败,使用/usr/local/mysql/support-files/mysql.server restart启动查看详细错误原因:

“mysql_safe Directory ‘/var/lib/mysql’ for UNIX socket file don’t exists.”

手动创建:

mkdir /var/lib/mysql

chown -R mysql:mysql /var/lib/mysql

再次启动

查看是否启动成功:

ps aux|grep mysql

11.登录mysql并设置root密码

/usr/local/mysql/bin/mysql -u root

set password=password('root');

退出sql命令行:

exit;

0x05 安装PHP

1.安装php依赖包

yum install libxml2 libxml2-devel openssl openssl-devel bzip2 bzip2-devel libcurl libcurl-devel libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel gmp gmp-devel libmcrypt libmcrypt-devel readline readline-devel libxslt libxslt-devel

2.下载php包并解压

cd /usr/local/src

wget https://www.php.net/distributions/php-7.2.0.tar.gz

tar -zxvf php-7.2.0.tar.gz

3.编译安装(到/usr/local/php目录)

cd php-7.2.0

./configure --prefix=/usr/local/php --disable-fileinfo --enable-fpm --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d --with-openssl --with-zlib --with-curl --enable-ftp --with-gd --with-xmlrpc --with-jpeg-dir --with-png-dir --with-freetype-dir --enable-gd-native-ttf --enable-mbstring --with-mcrypt=/usr/local/libmcrypt --enable-zip --enable-mysqlnd --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd --with-mysql-sock=/var/lib/mysql/mysql.sock --without-pear --enable-bcmath

(注:–with-mcrypt参数指定的是libmcrypt的安装目录。Php7不再使用mysql的库来支持mysql的连接,而是启用了mysqlnd来支持,所以php7的编译已经不再使用–with-mysql参数指定mysql的安装位置了,若想支持mysql,需要设置–enable-mysqlnd、–with-mysqli和–with-pdo-mysql=mysqlnd参数,–with-mysql-sock指定的是编译mysql时-DMYSQL_UNIX_ADDR参数指定的文件)

make

make install

4.将php包解压目录中的配置文件放置到正确位置(configure命令中的–with-config-file-path设置的位置)

cp php.ini-development /etc/php.ini

5.创建并设置php-fpm运行账号

groupadd www-data

useradd -M -g www-data -s /sbin/nologin www-data

cd /usr/local/php/etc

cp php-fpm.conf.default php-fpm.conf

vi php-fpm.conf

发现搜索不到“user”(设置运行账号的位置),但发现文件的最后一行:

img

所以:

cd php-fpm.d

cp www.conf.default www.conf

vi www.conf

搜索“user”设置运行账号:

user=www-data

group=www-data

6.配置nginx支持php

vi /usr/local/nginx/conf/nginx.conf

img

修改完成之后记得重启nginx服务:

systemctl start nginx.service

7.设置php-fpm为系统服务

vi /etc/systemd/system/php-fpm.service

文件内容:

[Unit]

Description=php-fpm

After=network.target

[Service]

Type=forking

ExecStart=/usr/local/php/sbin/php-fpm

PrivateTmp=True

[Install]

WantedBy=multi-user.target

8.设置php-fpm服务开机自启动

systemctl enable php-fpm.service

9.启动php-fpm

systemctl start php-fpm.service

查看是否启动成功:

ps aux | grep php-fpm

10.写一个php脚本测试nginx是否已支持php,php是否已支持mysql(到/usr/local/nginx/html/目录)

<?php
$servername = "192.168.202.128";
$username = "root";
$password = "root";
 
// 创建连接
$conn = mysqli_connect($servername, $username, $password);
 
// 检测连接
if (!$conn) {
    die("Connection failed: " . mysqli_connect_error());
}
echo "Connection successful";
?>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ri5oasEf-1627636075363)(C:\Users\lyz\AppData\Roaming\Typora\typora-user-images\image-20210705153307176.png)]

至此,LNMP环境搭建完成。

0x06 总体加固

1.关闭不需要的端口

只打开如下端口:

服务端口
ssh443(限制IP)
http80
https443
ftp21,20000-30000

2.配置https

3.设置目录权限

防止其他用户读取自己的敏感文件,防止配置信息泄露,防止其他用户在自己的目录中写shell。

0x07 Nginx加固

1.配置nginx的配置文件nginx.conf

#隐藏nginx的版本信息

http
{
    server_tokens off;
}

# 设置timeout设低来防御DOS攻击

http
{
    client_body_timeout    10;
    client_header_timeout  30;
    keepalive_timeout      30;
    send_timeout           10;
}

#封杀各种user-agent

除非经过伪装,恶意扫描工具一般都会在user-agent里留下某些特征字眼,比如scan,nmap等。我们可以用正则匹配这些字眼,从而达到过滤的目的,请根据需要调整。

if ($http_user_agent ~* "java|python|perl|ruby|curl|bash|echo|uname|base64|decode|md5sum|select|concat|httprequest|httpclient|nmap|scan" ) {

    return 403;
}

if ($http_user_agent ~* "" ) {
    return 403;
}

具体的非法user-agent还得慢慢从日志中逐个提取。

# 封杀特定的url

location ~ ^/(\.user.ini|\.ht|\.git|\.svn|\.project|LICENSE|README.md) {
      deny all;
    }

# 封杀特定的http方法和行为

if ($request_method !~ ^(GET|POST|HEAD)$ ) {

    return 405;

}

if ($http_range ~ "\d{9,}") {

    return 444;

}

# 强制网站使用域名访问,可以逃过IP扫描,比如

if ( $host !~* 'abc.com' ) {

    return 403;

}

# url 参数过滤敏感字

if ($query_string ~* "union.*select.*\(") { 

    rewrite ^/(.*)$  $host  permanent;

} 

if ($query_string ~* "concat.*\(") { 

    rewrite ^/(.*)$  $host  permanent;

}

#必须携带 referer

if ($http_referer = "" ) {

    return 403;

}

2.overlayfs

假设网站根目录/var/www/html有一个目录upload是要求可读写的,其他只读即可:

mkdir -p /data/lower
mkdir -p /data/upper
mkdir -p /data/worker
mv /var/www/html/upload /data/upper/
mv /var/www/html/* /data/lower/
mount -t overlayfs overlay -o lower=/data/lower,upper=/data/upper,workdir=/data/worker /var/www/html

0x08 MySQL加固

1.phpMyAdmin管理数据库限制

进入 phpMyAdmin 目录,找到 config.inc.php,如果没有,可以将根目录下的config.sample.inc.php 复制为 config.inc.php。
编辑 config.inc.php,添加下面两行代码,其中 192.168.202.128 是允许访问 phpMyAdmin 的 IP,Access denied 是未经授权访问时的提示信息:

?$ip_prefix = '111.18.89.174';

if (substr($_SERVER['REMOTE_ADDR'], 0, strlen($ip_prefix)) != $ip_prefix ) die('Access denied');

2.修改phpMyAdmin访问mysql数据库所占用的端口号

修改phpmyadmin目录下libraries下的配置文件config.default.php:

$cfg['Servers'][$i]['port'] = ''
#上面是默认语句,默认端口为3306
$cfg['Servers'][$i]['port'] = '3310';
#我们修改端口,指定为3301,这个可以自由指定

0x09 PHP加固

1.配置php的配置文件php.ini

#禁用不安全的PHP函数

disable_functions = show_source,system,shell_exec,passthru,exec,popen,proc_open,proc_get_status,phpinfo

#关闭php错误日志

display_errors = On
改为
display_errors = Off

#隐藏php版本信息

expose_php = On
改为
expose_php = Off

#禁止动态加载链接库

disable_dl = On;
改为
enable_dl = Off;

#禁用打开远程url

allow_url_fopen = On
改为
allow_url_fopen = Off

2.php上传分离

将文件上传到远程服务器,例如nfs等。当然,也可以调用事先写好的php接口。 即使有文件上传漏洞,但是文件被上传到了静态服务器上,木马等文件也无法执行。

例如:

php站点php.server.com,目录/data/site/www
静态文件站点static.server.com,目录/data/site/static

文件直接被传到了/data/site/static,上传的文件无法通过php.server.com访问,只能通过static.server.com访问,但是static.server.com不支持php,故恶意文件无法执行。

3.使用open_basedir限制虚拟主机跨目录访问

[HOST=php.server.com]
open_basedir=/data/site/php.server.com/:/tmp/

[HOST=test.server.com]
open_basedir=/data/site/test.server.com/:/tmp/

如上配置的意思是php.server.com下的php程序被限制在open_basedir配置的两个目录下, 不可以访问到其他目录。如果没有做以上的配置,那么test.server110.com与php.server.com的程序可以互相访问。
如果其中一个站点有漏洞被黑客植入了webshell,那么他可以通过这个站点拿下同一台服务器的其他站点,最后挂木马。

4.设置php用户只读

0x10 安全思考

如果不进行网站加固,则会导致配置信息泄露、敏感文件被读取。还会存在sql注入、文件上传、文件包含、csrf、xss等漏洞。黑客不仅可以轻而易举地获取到敏感数据,甚至还能利用这些漏洞获得webshell,得到网站的控制权,进而造成:

1.劫持网站,导致用户点击进入网站随即跳转到不良网站。

2.网站首页被篡改成恶意的内容,网站被挂马,被植入黑链。

3.网站文件被恶意删除。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值