下载证书

在nginx配置ssl

nginx使用ngx-http_ssl_module模块支持https协议

简单模式配置

daemon off;
pid tmp/nginx.pid;
error_log stderr debug;

events {
}

http {
    access_log tmp/access.log;
    default_type text/html;

    server {
        listen 443 ssl;

        # SSL 协议版本
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers  HIGH:!aNULL:!MD5;
        # 证书
        ssl_certificate ssl/ecc.pem;
        # 私钥
        ssl_certificate_key ssl/ecc.key;
        #定义算法
        #ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4";
        ##优先采取服务器算法
        ssl_prefer_server_ciphers  on;

        return 200 "https ok \n";
    }
}

server_name三种匹配方式:

  1. 精准匹配

  2. 通配符 www.bai*.com

  3. 正则匹配 server_name ~^www\.(\w+)\.com$;

  4. 特殊匹配格式

    • server_name ""; 匹配Host请求头不存在的情况。

    • server_name "-"; 无任何意义。

    • server_name "*"; 它被错误地解释为万能的名称。

server_name匹配顺序

1. 精确的名字

2. 以*号开头的最长通配符名称,例如 *.example.org

3. 以*号结尾的最长通配符名称,例如 mail.*

4. 第一个匹配的正则表达式(在配置文件中出现的顺序)

80端口重定向443

#两种方式
#第一种
server{
    listen        80;
    server_name    passport.test.goago.cn;
    #return 301 https://$server_name$document_uri;
    return 301 https://$host$document_uri;
}

#第二种
server{
    listen 80;
    server_name xxxx.com;
    rewrite ^(.*)$ https://${server_name}$1 permanent;
}

禁止访问未绑定的域名

因为访问相同的端口,然后回匹配server_name,如果没有找到就转发到同端口的第一个server服务上。

配置default_server来指定匹配不到的情况。

server {
  listen 80 default_server;
  server_name _;
  return 403;
}

server {
   listen 443 default_server;
   server_name _;
   return 403;
} 

一个虚拟主机可以配置多个证书

http {
    access_log tmp/access.log;
    default_type text/html;

    server {
        listen 443 ssl http2;
            server_name www.xlhtec.com
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_certificate ssl/ecc.pem;
        ssl_certificate_key ssl/ecc.key;
        ssl_certificate ssl/rsa.pem;
        ssl_certificate_key ssl/rsa.key;
        ...
    }
}

强制浏览器使用HTTPS协议通信,以免xss劫持

Strict-Transport-Security头部字段格式:

Strict-Transport-Security: max-age=<expire-time>
Strict-Transport-Security: max-age=<expire-time>; includeSubDomains
Strict-Transport-Security: max-age=<expire-time>; preload
  • max-age= 设置在浏览器收到这个请求后的秒的时间内凡是访问这个域名下的请求都使用HTTPS请求。

  • includeSubDomains (可选) 如果这个可选的参数被指定,那么说明此规则也适用于该网站的所有子域名。

  • preload (可选)查看预加载 HSTS获得详情。不是标准的一部分。

#nginx在server添加头部西悉尼
# 增加HSTS策略
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

max-age:设置单位时间内強制使用 HTTPS 连接
includeSubDomains:可选,所有子域同时生效
preload:可选,非规范值,用于定义使用『HSTS 预加载列表』
always:可选,保证所有响应都发送此响应头,包括各种內置错误响应
当用户进行 HTTPS 连接的时候,服务器会发送一个 Strict-Transport-Security 响应头:

限定可以从那些域名加载源文件脚本Content-Security-Policy

限制浏览器只加载和执行来自特定来源的脚本,从而防止恶意脚本注入和执行。XSS攻击

add_header Content-Security-Policy "default-src 'self' data: *.xxx.com  'unsafe-inline' 'unsafe-eval' mediastream: ";

#示例:所有请求设置了一个简单的 CSP 策略,允许从同一域名加载资源,
#      并允许从 Google 的 AJAX API 和 Google 字体加载脚本和样式
location / {
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 
   https://ajax.googleapis.com; style-src 'self' https://fonts.googleapis.com;";
    # 其他配置...
}
  • default-src: 设置网站默认的安全策略,适用于未指定安全策略的资源。

  • connect-src: 控制页面可以建立连接的来源,防止恶意站点通过连接发起攻击。

  • font-src: 控制字体资源的加载来源,防止加载恶意字体文件。

  • form-action: 控制表单提交的目标URL,防止跨站请求伪造(CSRF)攻击。

  • frame-ancestors: 控制嵌套的frame或iframe的来源,防止点击劫持攻击。

  • frame-src: 控制frame或iframe中加载的页面的来源,防止嵌套的恶意页面的攻击。

  • image-src: 控制图片资源的加载来源,防止加载恶意图片文件。

  • media-src: 控制媒体资源(如音频、视频)的加载来源,防止加载恶意媒体文件。

  • object-src: 控制object标签和embed标签中加载的内容的来源,防止加载恶意内容。

  • script-src: 控制JavaScript脚本的加载来源,防止执行恶意脚本。

  • style-src: 控制CSS样式表的加载来源,防止加载恶意样式表。

  • report-uri: 指定报告异常信息的URI,方便管理员及时发现和处理安全问题。

  • upgrade-insecure-requests: 要求浏览器将所有HTTP请求升级为HTTPS请求,提高安全性。

  • sandbox: 对页面中的某些元素进行限制,防止恶意代码对其进行操作。

指令值

指令示例

说明

*

img-src

允许任何内容。

'none'

img-src 'none'

不允许任何内容。

'self'

img-src 'self'

允许来自相同来源的内容(相同的协议、域名和端口)。

data

img-src data

允许data:协议(如base64编码的图片)。

www.a.com

img-src img.a.com

允许加载指定域名的资源。

*.a.com

img-src *.a.com

允许加载a.com任何子域的资源。

https://img.com

img-src https://img.com

允许加载img.com的https资源(协议需匹配)。

https:

img-src https:

允许加载https资源。

'unsafe-inline'

script-src 'unsafe-inline'

允许加载inline资源(例如常见的style属性,onclick,inline js和inline css等等)。

'unsafe-eval'

script-src 'unsafe-eval'

允许加载动态js代码,例如eval()。

用于控制浏览器在请求中发送的Referer信息

当用户在浏览器上点击一个链接时,会产生一个 HTTP 请求,用于获取新的页面内容,而在该请求的报头中包含一个Referrer,用以指定该请求是从哪个页面跳转页来的,常被用于分析用户来源等信息。但是也成为了一个不安全的因素

location / {
    add_header Referrer-Policy "no-referrer";
    return 200 'Hello, World!';
}

是否允许跨域请求

X-Permitted-Cross-Domain-Policies指示浏览器在处理跨域请求时应该遵循哪些策略。

location / {
    add_header X-Permitted-Cross-Domain-Policies none;
    add_header X-Permitted-Cross-Domain-Policies always;
    add_header X-Permitted-Cross-Domain-Policies use-credentials;
    add_header X-Permitted-Cross-Domain-Policies omit;
}

激活 keepalive 长连接,一个连接发送更多个请求

#在server中设置长连接
keepalive_timeout   70;

复用 SSL 会话参数,在并行并发的连接数中避免进行多次 SSL『握手』

#配置共享会话缓存大小
ssl_session_cache   shared:SSL:10m;
#配置会话超时时间
ssl_session_timeout 10m;

增强安全

#frame是否允许被嵌套。减少点击劫持
add_header X-Frame-Options semiorigin;
#禁止服务器自动解析资源类型
add_header X-Content-Type-Options nosniff;
#防XSS攻击
add_header X-Xss-Protection 1;

注意:
X-Frame-Options有三个值,deny全部拒绝确实是安全,但是我觉得没有必要。配置为semiorigin更好,允许同源的网址。
DENY:页面不能被嵌入到任何iframe或frame中;
SAMEORIGIN:页面只能被本站页面嵌入到iframe或者frame中;
ALLOW-FROM:页面允许frame或frame加载。

X-Xss-Protection表示开启xss防护:
0 :禁用
1 :启用
1; mode=block : 开启xss防护并通知浏览器阻止而不是过滤用户注入的脚本。

HTTP2

HTTP/2为了兼容HTTP。报文语义上仍然由Header + Body组成,只是将每个请求/应答虚拟成一个Stream。然后将HTTP报文切割成几块,每一块封装成一个二进制帧。一个Stream中的所有二进制帧头部包含相同的Stream ID ,不同Stream中的二进制Stream ID不相同。然后一个TCP连接中多个Stream可以并发请求,服务器也可以并发应答。并且Stream之间相互独立,不存在先后顺序。从而解决了HTTP中队首阻塞的问题。但是一个Stream中的多个二进制帧必须严格按照顺序进行请求/应答。

HTTP/2特性:

HTTP/2目前都是基于TLS的,所以HTTP/2连接之前需要经过TCP三次握手,TLS握手。若服务端支持HTTP/2,则在握手的过程中,通过TLS扩展字段ALPN告知客户端升级为HTTP/2通信。

对HTTP头部字段采用HPACK算法进行压缩,废除HTTP头部中起始行,将起始行中原来所要传递的信息编入头部字段中,这些字段称为伪头部字段,有别于原来的头部字段。比如:authority, :method:status分别表示域名,请求方法,状态码。

HTTP报文被拆分成多个二进制帧,虚拟出Stream的概念,对同一个Stream中的二进制帧携带相同的Stream ID,不同Stream的ID不能重复

HTTP2建立过程

  1. 首先进行TCP三次握手建立TCP连接

  2. SSL/TLS握手,握手过程中,若服务端支持HTTP/2协议,则在TLS子协议Encrypted Extensions扩展字段ALPN中携带h2

  3. 客户端需要回复一个特定的报文,称为Magic: PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n,该过程称为连接首页。后面双方就升级为HTTP/2协议进行通信。

  4. 双方可以在单个TCP连接中多个Stream并发请求/应答,称为多路复用。

Nginx配置需要http2模块支持

server {
    listen 443 ssl http2;
    server_name localhost;
}

OCSP stapling

OCSP 是客户端请求ca厂商OCSP证书状态是否有效,有效才能建立客户但服务端连接。

nginx允许客户端请求服务端后,服务端使用客户端携带的证书序列号访问CA的OCSP证书服务器,查询证书状态并进行缓存,返回给客户端当前证书状态。

# 开启OCSP stapling     
ssl_stapling on | off;

# Nginx是否需要验证OCSP服务器的响应(比如证书吊销状态)
# 若配置为on就需要使用CA的公钥对响应结果解密。
# 就需要使用ssl_trusted_certificate指定证书链, 
# 但若ssl_cetificate中已经包含了完整的证书链,就不用指定了。
ssl_stapling_verify on | off;

ssl_trusted_certificate FILE;

# 若Nginx无法请求到OCSP服务器的响应,比如网络不好等等,也可以自己手动跟新响应,
# 然后将响应保存到一个DER格式的文件中,然后指定该文件。
ssl_stapling_file DER_FILE; 
# 自己指定OCSP服务,默认包含在证书中,不用指定。
ssl_stapling_responder http://OCSP_SERVER;
http {
    server {
        listen 443 ssl http2;

        # OCSP stapling
        ssl_stapling on;
    }
}

完整示例

域名1:aaa.com

域名2:bbb.com

公网ip地址: 217.9.9.9

user liych;
worker_processes  1;

error_log  /var/log/nginx/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

pid        /var/run/nginx.pid;


events {
    worker_connections  2048;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$http_host" "$request" > "$upstream_addr" '
                      '$status $body_bytes_sent "$http_referer" '
                     '"$http_user_agent" "$http_x_forwarded_for"';
    #access_log  logs/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;

    # 关闭Nginx版本号显示
    server_tokens       off;

    proxy_buffering off;
    keepalive_timeout   300;
    keepalive_requests  200;
    client_max_body_size 20M;
    types_hash_max_size 2048;

    fastcgi_connect_timeout 300s;
    fastcgi_send_timeout 300s;
    fastcgi_read_timeout 300s;
    fastcgi_buffer_size 512k;
    fastcgi_buffers 10 512k;
    fastcgi_busy_buffers_size 1024k;
    fastcgi_temp_file_write_size 1024k;

    open_file_cache max=65535 inactive=60s;
    open_file_cache_valid 80s;
    server_names_hash_bucket_size 2048;
    client_header_buffer_size 128k;
    client_body_buffer_size 512k;
    large_client_header_buffers 4 128k;

    proxy_hide_header X-Powered-By;
    proxy_hide_header Server;
    proxy_connect_timeout 300;
    proxy_send_timeout 300;
    proxy_read_timeout 300;
    proxy_buffer_size 4k;
    proxy_buffers 4 64k;
    proxy_busy_buffers_size 128k;
    proxy_temp_file_write_size 128k;
    proxy_temp_path cache/mytemp_cache;
    proxy_cache_path cache/mytest_cache levels=1:2 keys_zone=mytest:20m inactive=24h max_size=1000m;
    proxy_intercept_errors on;

    gzip_min_length  1k;
    gzip_buffers     4 16k;
    gzip_comp_level  4;
    gzip_types      text/plain application/javascript image/png text/css text/xml text/vnd.wap.wml text/x-component application/x-javascript image/gif image/jpeg application/atom+xml application/rss+xml application/octet-stream application/x-rar-compressed application/json;
    gzip_http_version 1.1;
    gzip_vary on;
    gzip_disable "msie6";
    gzip  on;

    #请求限流
    limit_req_zone $binary_remote_addr zone=www_sym:10m rate=150r/s;
    limit_req_log_level error;    

    #连接数限流
    limit_conn_zone $binary_remote_addr zone=perip:10m;
    limit_conn_zone $server_name zone=perserver:10m;
    limit_conn_log_level error;
    
    #配置国家IP库
    geoip2 /GeoLite2-Country.mmdb {
      auto_reload 9m;
      $geoip2_country_name country names en;
      $geoip2_data_country_code country iso_code;
    }

    # 配置城市IP库
    geoip2 /GeoLite2-City.mmdb {
        auto_reload 5m;
        $geoip2_data_city_name city names en;
        $geoip2_data_province_name subdivisions 0 names en;
        $geoip2_data_province_isocode subdivisions 0 iso_code;
        $geoip2_continent_code continent code;
    }


    #国家IP过滤,只允许中国
    map $geoip2_data_country_code $allowed_country {
      default yes;
      CN no;
    }

    #设置白名单,在下列白名单中不限速
    geo $is_whitelist {
        default 0;
        172.17.0.0/16 1;
     }

     map $is_whitelist $limit_key {
         1 "";
         0 $binary_remote_addr;  
     } 
    #强制使用https  443端口
    server {
       listen 80;
       server_name _;
       return 301 https://$host$document_uri;
    }
    #如果访问的域名没匹配到,就直接403
    server {
       listen 443 default_server;
       server_name _;
       # 证书
        ssl_certificate /default.pem;
        # 私钥
        ssl_certificate_key /default.key;
       return 403;
    }
    #开启https
    server {
        listen       443 ssl;
        server_name www.liutx.com liutx.com;
        charset utf-8;
        client_max_body_size 300m;

        access_log  /xxxx_accept.log  main;

        #tls认证
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        #证书
        ssl_certificate liutx.com.pem;
        #密钥
        ssl_certificate_key liutx.com.key;
        #HSTS策略,告诉浏览器age时间内必须https访问
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
        #服务端缓存ssl证书状态并一起发给客户端,
        ssl_stapling on;
        #配置共享会话缓存大小
        ssl_session_cache   shared:SSL:10m;
        #配置会话超时时间
        ssl_session_timeout 10m;
        #减少点击劫持
        add_header X-Frame-Options semiorigin;
        #禁止服务器自动解析资源类型
        add_header X-Content-Type-Options nosniff;
        #防XSS攻击
        add_header X-Xss-Protection 1;
        #只允许添加自身域名源文件
        add_header Content-Security-Policy "default-src 'self'";
      

        # 启用压缩,压缩等级为9级,压缩t
        gzip on;
        gzip_comp_level 9;
        gzip_types text/css text/plan text/xml application/javascript application/x-javascript application/html application/xml image/png image/jpg image/jpeg image/gif image/webp image/svg+xml;

        #限请求
        limit_req zone=www_sym burst=50 nodelay;
        #限流连接
        limit_conn perserver 500;
        limit_conn perip 150;

        # 如果超过设定的每秒150个连接数这个阈值,则返回448状态码给客户端
        limit_req_status 448;
   
        # 如果超过设定的每个IP每秒150个连接数这个阈值,则返回449状态码给客户端
        limit_conn_status 449;
   
        # 限制客户端速度只能到150k
        #limit_rate        150k;

        # 防盗链,如果请求的头不是test.if010.com就是无效的,则返回449状态码给客户端   
        #valid_referers none blocked test.if010.comm;
        #if ($invalid_referer) {
        #    return 449;
        #}

        # 做判断,如果国家不是中国,就返回451状态码给客户端;  
        if ($geoip2_data_country_code != CN ) {
            return 451;
        }
        
        # 添加客户端的IP头
        add_header client-country $geoip2_data_country_code;
        
        #限制国外IP
        if ($allowed_country = yes) {
           # return https://www.baidu.com;
           # return /home/japan;
           return 404;
        }

        # 防爬虫,如果UA是底下任意一个值,就判定为蜘蛛爬虫,则返回453给客户端
        if ($http_user_agent ~* "python|curl|java|wget|httpclient|okhttp|qihoobot|Scrubby|YodaoBot|yahoo-blogs/v3.9|Gigabot|yahoo-mmcrawler|Teoma|Robozilla|Bingbot|Slurp|Baiduspider|Googlebot|googlebot-mobile|googlebot-image|Mediapartners-Google|Adsbot-Google|Feedfetcher-Google|Yahoo!Slurp|Yahoo!Slurp China|YoudaoBot|Sosospider|MSNBot|ia_archiver|twiceler|psbot") {
            return 453;
        }
        #测试界面,后续改为反向代理java程序
        location / {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $remote_addr;
            root   N025/;
            index  index.html index.htm;
        }

        error_page  400 401 402 403 404 500 502 503 504 /error.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
        
    }

}

文章作者: 刘同学
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 刘同学的小站
中间件 Nginx
喜欢就支持一下吧