安全开发运维必备的Nginx代理Web服务器性能优化与安全加固配置

安全开发运维必备的Nginx代理Web服务器性能优化与安全加固配置,第1张

为了更好的指导部署与测试艺术升系统nginx网站服务器高性能同时下安全稳定运行,需要对nginx服务进行调优与加固

本次进行Nginx服务调优加固主要从以下几个部分:

本文档仅供内部使用,禁止外传,帮助研发人员,运维人员对系统长期稳定的运行提供技术文档参考。

Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器。Nginx作为负载均衡服务器, Nginx 既可以在内部直接支持 Rails 和 PHP 程序对外进行服务,也可以支持作为 HTTP代理服务器对外进行服务。

Nginx版本选择:

项目结构:

Nginx文档帮助: http://nginx.org/en/docs/

Nginx首页地址目录: /usr/share/nginx/html

Nginx配置文件:

localtion 请求匹配的url实是一个正则表达式:

Nginx 匹配判断表达式:

例如,匹配末尾为如下后缀的静态并判断是否存在该文件, 如不存在则404。

查看可用模块编译参数:http://nginx.org/en/docs/configure.html

http_gzip模块

开启gzip压缩输出(常常是大于1kb的静态文件),减少网络传输

http_fastcgi_module模块

nginx可以用来请求路由到FastCGI服务器运行应用程序由各种框架和PHP编程语言等。可以开启FastCGI的缓存功能以及将静态资源进行剥离,从而提高性能。

keepalive模块

长连接对性能有很大的影响,通过减少CPU和网络开销需要开启或关闭连接

http_ssl_module模块

Nginx开启支持Https协议的SSL模块

Linux内核参数部分默认值不适合高并发,Linux内核调优,主要涉及到网络和文件系统、内存等的优化,

下面是我常用的内核调优配置:

文件描述符

文件描述符是 *** 作系统资源,用于表示连接、打开的文件,以及其他信息。NGINX 每个连接可以使用两个文件描述符。

例如如果NGINX充当代理时,通常一个文件描述符表示客户端连接,另一个连接到代理服务器,如果开启了HTTP 保持连接,这个比例会更低(译注:为什么更低呢)。

对于有大量连接服务的系统,下面的设置可能需要调整一下:

精简模块:Nginx由于不断添加新的功能,附带的模块也越来越多,建议一般常用的服务器软件使用源码编译安装管理

(1) 减小Nginx编译后的文件大小

(2) 指定GCC编译参数

修改GCC编译参数提高编译优化级别稳妥起见采用 -O2 这也是大多数软件编译推荐的优化级别。

GCC编译参数优化 [可选项] 总共提供了5级编译优化级别:

常用编译参数:

缓存和压缩与限制可以提高性能

NGINX的一些额外功能可用于提高Web应用的性能,调优的时候web应用不需要关掉但值得一提,因为它们的影响可能很重要。

简单示例:

1) 永久重定向

例如,配置 http 向 https 跳转 (永久)

nginx配置文件指令优化一览表

描述:Nginx因为安全配置不合适导致的安全问题,Nginx的默认配置中存在一些安全问题,例如版本号信息泄露、未配置使用SSL协议等。

对Nginx进行安全配置可以有效的防范一些常见安全问题,按照基线标准做好安全配置能够减少安全事件的发生,保证采用Nginx服务器系统应用安全运行

Nginx安全配置项:

温馨提示: 在修改相应的源代码文件后需重新编译。

设置成功后验证:

应配置非root低权限用户来运行nginx服务,设置如下建立Nginx用户组和用户,采用user指令指运行用户

加固方法:

我们应该为提供的站点配置Secure Sockets Layer Protocol (SSL协议),配置其是为了数据传输的安全,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。

不应使用不安全SSLv2、SSLv3协议即以下和存在脆弱性的加密套件(ciphers), 我们应该使用较新的TLS协议也应该优于旧的,并使用安全的加密套件。

HTTP Referrer Spam是垃圾信息发送者用来提高他们正在尝试推广的网站的互联网搜索引擎排名一种技术,如果他们的垃圾信息链接显示在访问日志中,并且这些日志被搜索引擎扫描,则会对网站排名产生不利影响

加固方法:

当恶意攻击者采用扫描器进行扫描时候利用use-agent判断是否是常用的工具扫描以及特定的版本,是则返回错误或者重定向

Nginx支持webdav,虽然默认情况下不会编译。如果使用webdav,则应该在Nginx策略中禁用此规则。

加固方法: dav_methods 应设置为off

当访问一个特制的URL时,如"../nginx.status",stub_status模块提供一个简短的Nginx服务器状态摘要,大多数情况下不应启用此模块。

加固方法:nginx.conf文件中stub_status不应设置为:on

如果在浏览器中出现Nginx自动生成的错误消息,默认情况下会包含Nginx的版本号,这些信息可以被攻击者用来帮助他们发现服务器的潜在漏洞

加固方法: 关闭"Server"响应头中输出的Nginx版本号将server_tokens应设置为:off

client_body_timeout设置请求体(request body)的读超时时间。仅当在一次readstep中,没有得到请求体,就会设为超时。超时后Nginx返回HTTP状态码408(Request timed out)。

加固方法:nginx.conf文件中client_body_timeout应设置为:10

client_header_timeout设置等待client发送一个请求头的超时时间(例如:GET / HTTP/1.1)。仅当在一次read中没有收到请求头,才会设为超时。超时后Nginx返回HTTP状态码408(Request timed out)。

加固方法:nginx.conf文件中client_header_timeout应设置为:10

keepalive_timeout设置与client的keep-alive连接超时时间。服务器将会在这个时间后关闭连接。

加固方法:nginx.conf文件中keepalive_timeout应设置为:55

send_timeout设置客户端的响应超时时间。这个设置不会用于整个转发器,而是在两次客户端读取 *** 作之间。如果在这段时间内,客户端没有读取任何数据,Nginx就会关闭连接。

加固方法:nginx.conf文件中send_timeout应设置为:10

GET和POST是Internet上最常用的方法。Web服务器方法在RFC 2616中定义禁用不需要实现的可用方法。

加固方法:

limit_zone 配置项限制来自客户端的同时连接数。通过此模块可以从一个地址限制分配会话的同时连接数量或特殊情况。

加固方法:nginx.conf文件中limit_zone应设置为:slimits $binary_remote_addr 5m

该配置项控制一个会话同时连接的最大数量,即限制来自单个IP地址的连接数量。

加固方法:nginx.conf 文件中 limit_conn 应设置为: slimits 5

加固方法:

加固方法:

解决办法:

描述后端获取Proxy后的真实Client的IP获取需要安装--with-http_realip_module,然后后端程序采用JAVA(request.getAttribute("X-Real-IP"))进行获取

描述: 如果要使用geoip地区选择,我们需要再nginx编译时加入 --with-http_geoip_module 编译参数。

描述: 为了防止外部站点引用我们的静态资源,我们需要设置那些域名可以访问我们的静态资源。

描述: 下面收集了Web服务中常规的安全响应头, 它可以保证不受到某些攻击,建议在指定的 server{} 代码块进行配置。

描述: 为了防止某些未备案的域名或者恶意镜像站域名绑定到我们服务器上, 导致服务器被警告关停,将会对业务或者SEO排名以及企业形象造成影响,我们可以通过如下方式进行防范。

执行结果:

描述: 有时你的网站可能只需要被某一IP或者IP段的地址请求访问,那么非白名单中的地址访问将被阻止访问, 我们可以如下配置

常用nginx配置文件解释:

(1) 阿里巴巴提供的Concat或者Google的PageSpeed模块实现这个合并文件的功能。

(2) PHP-FPM的优化

如果您高负载网站使用PHP-FPM管理FastCGI对于PHP-FPM的优化非常重要

(3) 配置Resin on Linux或者Windows为我们可以打开 resin-3.1.9/bin/httpd.sh 在不影响其他代码的地方加入:-Dhttps.protocols=TLSv1.2, 例如

原文地址: https://blog.weiyigeek.top/2019/9-2-122.html

用 iptable 屏蔽某个网站的话也会屏蔽同一 VPS 上的其他网站的访问。

所以正统的办法还是用 GeoIP 配合对应的 web 服务器模块,比如:apache + mod_geoip 或者 nginx + http_geoip_module 等。

Nginx 的配置文件使用的就是一门微型的编程语言,许多真实世界里的 Nginx 配置文件其实就是一个一个的小程序。当然,是不是“图灵完全的”暂且不论,至少据我观察,它在设计上受 Perl 和 Bourne Shell 这两种语言的影响很大。在这一点上,相比 Apache 和 Lighttpd 等其他 Web 服务器的配置记法,不能不说算是 Nginx 的一大特色了。既然是编程语言,一般也就少不了“变量”这种东西(当然,Haskell 这样奇怪的函数式语言除外了)。

熟悉 Perl、Bourne Shell、C/C++ 等命令式编程语言的朋友肯定知道,变量说白了就是存放“值”的容器。而所谓“值”,在许多编程语言里,既可以是 3.14 这样的数值,也可以是 hello world 这样的字符串,甚至可以是像数组、哈希表这样的复杂数据结构。然而,在 Nginx 配置中,变量只能存放一种类型的值,因为也只存在一种类型的值,那就是字符串。

比如我们的 nginx.conf 文件中有下面这一行配置:

set $a "hello world"

我们使用了标准 ngx_rewrite 模块的 set 配置指令对变量 $a 进行了赋值 *** 作。特别地,我们把字符串 hello world 赋给了它。

我们看到,Nginx 变量名前面有一个 $ 符号,这是记法上的要求。所有的 Nginx 变量在 Nginx 配置文件中引用时都须带上 $ 前缀。这种表示方法和 Perl、PHP 这些语言是相似的。

虽然 $ 这样的变量前缀修饰会让正统的 Java 和 C# 程序员不舒服,但这种表示方法的好处也是显而易见的,那就是可以直接把变量嵌入到字符串常量中以构造出新的字符串:

set $a hello

set $b "$a, $a"

这里我们通过已有的 Nginx 变量 $a 的值,来构造变量 $b 的值,于是这两条指令顺序执行完之后,$a 的值是 hello,而 $b 的值则是 hello, hello. 这种技术在 Perl 世界里被称为“变量插值”(variable interpolation),它让专门的字符串拼接运算符变得不再那么必要。我们在这里也不妨采用此术语。

我们来看一个比较完整的配置示例:

server {

listen 8080

location /test {

set $foo hello

echo "foo: $foo"

}

}

这个例子省略了 nginx.conf 配置文件中最外围的 http 配置块以及 events 配置块。使用 curl 这个 HTTP 客户端在命令行上请求这个 /test 接口,我们可以得到

$ curl 'http://localhost:8080/test'

foo: hello

这里我们使用第三方 ngx_echo 模块的 echo 配置指令将 $foo 变量的值作为当前请求的响应体输出。

我们看到,echo 配置指令的参数也支持“变量插值”。不过,需要说明的是,并非所有的配置指令都支持“变量插值”。事实上,指令参数是否允许“变量插值”,取决于该指令的实现模块。

如果我们想通过 echo 指令直接输出含有“美元符”($)的字符串,那么有没有办法把特殊的 $ 字符给转义掉呢?答案是否定的(至少到目前最新的 Nginx 稳定版 1.0.10)。不过幸运的是,我们可以绕过这个限制,比如通过不支持“变量插值”的模块配置指令专门构造出取值为 $ 的 Nginx 变量,然后再在 echo 中使用这个变量。看下面这个例子:

geo $dollar {

default "$"

}

server {

listen 8080

location /test {

echo "This is a dollar sign: $dollar"

}

}

测试结果如下:

$ curl 'http://localhost:8080/test'

This is a dollar sign: $

这里用到了标准模块 ngx_geo 提供的配置指令 geo 来为变量 $dollar 赋予字符串 "$",这样我们在下面需要使用美元符的地方,就直接引用我们的 $dollar 变量就可以了。其实 ngx_geo 模块最常规的用法是根据客户端的 IP 地址对指定的 Nginx 变量进行赋值,这里只是借用它以便“无条件地”对我们的 $dollar 变量赋予“美元符”这个值。

在“变量插值”的上下文中,还有一种特殊情况,即当引用的变量名之后紧跟着变量名的构成字符时(比如后跟字母、数字以及下划线),我们就需要使用特别的记法来消除歧义,例如:

server {

listen 8080

location /test {

set $first "hello "

echo "${first}world"

}

}

这里,我们在 echo 配置指令的参数值中引用变量 $first 的时候,后面紧跟着 world 这个单词,所以如果直接写作 "$firstworld" 则 Nginx “变量插值”计算引擎会将之识别为引用了变量 $firstworld. 为了解决这个难题,Nginx 的字符串记法支持使用花括号在 $ 之后把变量名围起来,比如这里的 ${first}. 上面这个例子的输出是:

$ curl 'http://localhost:8080/test

hello world

set 指令(以及前面提到的 geo 指令)不仅有赋值的功能,它还有创建 Nginx 变量的副作用,即当作为赋值对象的变量尚不存在时,它会自动创建该变量。比如在上面这个例子中,如果 $a 这个变量尚未创建,则 set 指令会自动创建 $a 这个用户变量。如果我们不创建就直接使用它的值,则会报错。例如

1

2

3

4

5

6

server {

listen 8080

location /bad {

echo $foo

}

}

此时 Nginx 服务器会拒绝加载配置:

1

[emerg] unknown "foo" variable

是的,我们甚至都无法启动服务!

有趣的是,Nginx 变量的创建和赋值 *** 作发生在全然不同的时间阶段。Nginx 变量的创建只能发生在 Nginx 配置加载的时候,或者说 Nginx 启动的时候;而赋值 *** 作则只会发生在请求实际处理的时候。这意味着不创建而直接使用变量会导致启动失败,同时也意味着我们无法在请求处理时动态地创建新的 Nginx 变量。

Nginx 变量一旦创建,其变量名的可见范围就是整个 Nginx 配置,甚至可以跨越不同虚拟主机的 server 配置块。我们来看一个例子:

server {

listen 8080

location /foo {

echo "foo = [$foo]"

}

location /bar {

set $foo 32

echo "foo = [$foo]"

}

}

这里我们在 location /bar 中用 set 指令创建了变量 $foo,于是在整个配置文件中这个变量都是可见的,因此我们可以在 location /foo 中直接引用这个变量而不用担心 Nginx 会报错。

下面是在命令行上用 curl 工具访问这两个接口的结果:

$ curl 'http://localhost:8080/foo'

foo = []

$ curl 'http://localhost:8080/bar'

foo = [32]

$ curl 'http://localhost:8080/foo'

foo = []

从这个例子我们可以看到,set 指令因为是在 location /bar 中使用的,所以赋值 *** 作只会在访问 /bar 的请求中执行。而请求 /foo 接口时,我们总是得到空的 $foo 值,因为用户变量未赋值就输出的话,得到的便是空字符串。

从这个例子我们可以窥见的另一个重要特性是,Nginx 变量名的可见范围虽然是整个配置,但每个请求都有所有变量的独立副本,或者说都有各变量用来存放值的容器的独立副本,彼此互不干扰。比如前面我们请求了 /bar 接口后,$foo 变量被赋予了值 32,但它丝毫不会影响后续对 /foo 接口的请求所对应的 $foo 值(它仍然是空的!),因为各个请求都有自己独立的 $foo 变量的副本。

对于 Nginx 新手来说,最常见的错误之一,就是将 Nginx 变量理解成某种在请求之间全局共享的东西,或者说“全局变量”。而事实上,Nginx 变量的生命期是不可能跨越请求边界的。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/bake/11387591.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-15
下一篇 2023-05-15

发表评论

登录后才能评论

评论列表(0条)

保存