根据RFC 2817

问题描述:

HTTP升级到Nginx中的TLS我一直在研究如何将HTTP连接升级到TLS,并实现跨端代理的端到端隧道。我希望在这个隧道中使用客户端证书,在几跳之后在接收端进行处理。 我读RFC 2817(HTTP升级到TLS),似乎这是可能的。我只是不知道如何使用Nginx作为Nginx新手。根据RFC 2817

我想知道我是否在做一个完整的noob错误,或者如果这在Nginx中是完全可能的。

我Nginx的实例1以下配置的HTTP模块:

http { 
    include  mime.types; 
    default_type application/octet-stream; 
    log_format main '$remote_addr - $remote_user [$time_local] ' 
        '$ssl_protocol/$ssl_cipher ' 
        '$ssl_client_cert ' 
        '$ssl_client_raw_cert ' 
        'HTTP UPGRADE: $http_upgrade ' 
        '"$request" $status $body_bytes_sent ' 
        '"$http_referer" "$http_user_agent"'; 

access_log logs/access.log; 

sendfile  on; 
keepalive_timeout 65; 

map $http_upgrade $connection_upgrade { 
    default upgrade; 
    ''  close; 
} 

server { 
    listen 80 default_server; 
    listen [::]:80 default_server; 

    # Redirect all HTTP requests to HTTPS with a 301 Moved Permanently response. 
    return 301 https://$host$request_uri; 
} 

# HTTPS server 
server { 
    listen  443 ssl; 
    listen  [::]:443 ssl; 
    server_name localhost; 

    access_log logs/access-ssl.log main; 

    ssl_certificate  /root/certs/server.crt; 
    ssl_certificate_key /root/certs/server.key; 
    ssl_session_timeout 1d; 
    ssl_session_cache shared:SSL:50m; 
    ssl_session_tickets off; 

    # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits 
    ssl_dhparam /root/certs/dhparams.pem; 

    # modern configuration. tweak to your needs. 
    ssl_protocols TLSv1.2; 
    ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; 
    ssl_prefer_server_ciphers on; 

    # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months) 
    add_header Strict-Transport-Security max-age=15768000; 

    location/{ 
     proxy_set_header Host $host; 
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
     proxy_set_header X-Real-IP $remote_addr; 
     proxy_set_header Upgrade $http_upgrade; 
     proxy_set_header Connection "Upgrade"; 
     proxy_pass https://10.0.3.4/; 
    } 

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

第二Nginx的实例具有以下配置具有相当多,除了一个区别proxy_pass https://10.0.3.5/index.html

最后一个相同的配置Nginx实例具有以下配置:

http { 
include  mime.types; 
default_type application/octet-stream; 
log_format main '$remote_addr - $remote_user [$time_local] ' 
        '$ssl_protocol/$ssl_cipher ' 
        '$ssl_client_cert ' 
        '$ssl_client_raw_cert ' 
        'HTTP UPGRADE: $http_upgrade ' 
        '"$request" $status $body_bytes_sent ' 
        '"$http_referer" "$http_user_agent"'; 

access_log logs/access.log; 

sendfile  on; 
keepalive_timeout 65; 

map $http_upgrade $connection_upgrade { 
    default upgrade; 
    ''  close; 
} 

server { 
    listen 80 default_server; 
    listen [::]:80 default_server; 

    # Redirect all HTTP requests to HTTPS with a 301 Moved Permanently response. 
    return 301 https://$host$request_uri; 
} 

# HTTPS server 
server { 
    listen  443 ssl; 
    listen  [::]:443 ssl; 
    server_name localhost; 

    access_log logs/access-ssl.log main; 

    ssl_certificate  /root/certs/server.crt; 
    ssl_certificate_key /root/certs/server.key; 
    ssl_session_timeout 1d; 
    ssl_session_cache shared:SSL:50m; 
    ssl_session_tickets off; 

    # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits 
    ssl_dhparam /root/certs/dhparams.pem; 

    # modern configuration. tweak to your needs. 
    ssl_protocols TLSv1.2; 
    ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; 
    ssl_prefer_server_ciphers on; 

    # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months) 
    add_header Strict-Transport-Security max-age=15768000; 

    location/{ 
     root html; 
     index index.html index.htm; 
    } 

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

当我使用HTTPS访问URL时,确实得到响应但没有任何回合客户证书打印在日志中。当我只使用HTTP时,我得到了301响应。这是两个电话我提出: $ curl -k -i --cert /root/certs/client-cert.pem --key /root/certs/client-key.pem --header "Upgrade: TLS/1.2" --header "Connection: Upgrade" https://10.0.3.3/

$ curl -k -i --cert /root/certs/client-cert.pem --key /root/certs/client-key.pem --header "Upgrade: TLS/1.2" --header "Connection: Upgrade" http://10.0.3.3/

RFC 2817定义了TLS升级方法有两种:连接请求,并Connection: Upgrade

CONNECT是浏览器在使用明确配置的HTTP代理时完成的HTTP请求。它不能用于透明代理或反向代理。与例如squid相反,nginx是一个Web服务器,而不是HTTP代理(从浏览器的角度来看),因此不会实现CONNECT请求。

至于连接升级到RFC 2817中指定的TLS:这只是一个想法,没有浏览器支持这一点。这种升级机制实际上在今天的浏览器中使用,但不用于升级到TLS,而仅用于WebSockets。

+0

非常感谢你的澄清。我打算使用在应用程序级别实现的此功能,并且我不打算将它用于浏览器。这个想法是让一个应用程序进行调用,呈现自己的证书,并用请求的资源一直代理到一个服务。到达最终服务的跳数有多个,并且最终服务将根据原始发件人的证书对请求进行身份验证和授权。 – Tempo

+0

@Tempo:由于TLS是端到端加密,因此只有端点可以请求并验证客户端证书。这意味着无法通过客户端证书或中间的某些软件(nginx或其他)中的请求资源来选择端点,并且仍然能够将客户端证书无损转发到端点。 –

+0

非常感谢您的评论,非常感谢。如果在这种情况下TLS(和HTTPS隧道/升级)不是一个选项,是否有任何其他经过验证的解决方案可以用来实现所需的结果?除了从零开始实施自定义协议?即使对于专有协议,我甚至不知道如何开始实施它。作为一个Nginx模块呢? – Tempo