nginx: Làm thế nào để ngăn chặn một khối máy chủ SSL được đặt tên chính xác hoạt động như một điểm thu hút cho tất cả SSL


17

Tôi có một máy chủ web với nhiều máy chủ ảo. Chỉ có 1 trong số đó là SSL. Vấn đề là, vì không có khối máy chủ bắt kịp nghe SSL, mọi yêu cầu https đến các trang web khác đều được cung cấp bởi khối 1 SSL.

Cấu hình của tôi, về cơ bản, trông như thế này:

# the catch all
server {
  listen 80 default;

  # I could add this, but since I have no default cert, I cannot enable SSL,
  # and this listen ends up doing nothing (apparently).
  # listen 443; 

  server_name _;
  # ...
}

# some server
server {
  listen 80;
  server_name server1.com;
  # ...
}

# some other server ...
server {
  listen 80;
  server_name server2.com;
  # ...
}

# ... and it's https equivalent
server {
  listen 443;
  ssl on;
  server_name server2.com;
  # ...
}

Bây giờ vì không có trình nghe mặc định cho 443, nên một yêu cầu như thế https://server1.comcuối cùng sẽ được phục vụ bởi server2.comkhối https. Điều này tuân theo logic cho server_nametrong các tài liệu.

Nếu không khớp, một khối máy chủ {...} trong tệp cấu hình sẽ được sử dụng dựa trên thứ tự sau:

  1. khối máy chủ có chỉ thị nghe phù hợp được đánh dấu là [default | default_server]
  2. khối máy chủ đầu tiên có lệnh nghe phù hợp (hoặc nghe ngầm 80;)

Giải pháp ưa thích cho vấn đề này là gì? Tôi có cần thiết lập chứng chỉ giả cho việc bắt tất cả khối máy chủ để tôi có thể nghe trên 443 và xử lý các yêu cầu xấu không? Có một tham số mà tôi không biết về việc buộc một tên máy chủ chính xác khớp với server?


Bạn muốn điều gì xảy ra khi mọi người cố gắng truy cập các trang web khác bằng https?
David Schwartz

Lý tưởng nhất là tôi muốn nginx hoàn toàn không phục vụ https trừ khi tên máy chủ trùng khớp hoặc để nó chuyển hướng đến http tại cùng một máy chủ.
số1311407

Câu trả lời:


9

Lý tưởng nhất là tôi muốn nginx hoàn toàn không phục vụ https trừ khi tên máy chủ trùng khớp hoặc để nó chuyển hướng đến http tại cùng một máy chủ.

Không phải là có thể. Kết nối từ ứng dụng khách đến https://foo.example.com/ không thể được chấp nhận bởi bất kỳ thứ gì ngoại trừ chứng chỉ SSL có "foo.example.com" là một trong những tên của nó. Không có cơ hội để chuyển hướng cho đến khi kết nối SSL được chấp nhận.

Nếu bạn định cấu hình từng trang web cho SSL, người dùng nhấp qua lỗi chứng chỉ sẽ nhận được trang web họ yêu cầu. Nếu bạn định cấu hình trang web "bắt tất cả" cho SSL chỉ cung cấp trang lỗi và định cấu hình lưu trữ ảo dựa trên tên cho một trang web được cho là hỗ trợ SSL, bạn có thể cung cấp trang lỗi cho khách hàng.

Lưu trữ ảo SSL và HTTP không chơi tốt với nhau.


Đây là những gì tôi thu thập sau khi đọc các tài liệu. Tôi chỉ hy vọng tôi đã bỏ lỡ một cái gì đó. Tôi hoàn toàn không quan tâm đến các cảnh báo SSL. Tôi chỉ không muốn ai đó vào server1.com và thấy mình đang xem trang chủ của server2.com ... Có thực sự không có cách nào để nói với nginx không chấp nhận yêu cầu không?
số1311407

Nếu nó không chấp nhận yêu cầu, trang web đầu tiên sẽ không hoạt động. Nó phải chấp nhận yêu cầu tìm hiểu trang web nào người dùng đang cố truy cập.
David Schwartz

2
"Kết nối từ máy khách đến foo.example.com không thể được chấp nhận bởi bất kỳ thứ gì ngoại trừ chứng chỉ SSL có" foo.example.com "là một trong những tên của nó." - Điều này không chính xác, máy chủ sẽ chấp nhận yêu cầu và tùy thuộc vào máy khách để xác minh rằng DN được yêu cầu khớp với chứng chỉ máy chủ DN.
ColinM

4

Cách duy nhất để làm là tạo chứng chỉ SSL tự ký và sử dụng nó để giành quyền kiểm soát các yêu cầu https đến. Bạn có thể tạo chứng chỉ SSL tự ký của mình trong một vài bước đơn giản được nêu trong bài đăng này .

Giả sử bạn tạo chứng chỉ tự ký với tên tệp là server.crt. Sau đó, bạn sẽ nối các phần sau trong cấu hình nginx của mình:

server {
    listen  443;

    ssl    on;
    ssl_certificate         /etc/nginx/ssl/server.crt;
    ssl_certificate_key     /etc/nginx/ssl/server.key;

    server_name server1.com;

    keepalive_timeout 60;
    rewrite ^       http://$server_name$request_uri? permanent;
}

Bạn vẫn sẽ nhận được thông báo cảnh báo SSL của trình duyệt, nhưng ít nhất bạn sẽ có quyền kiểm soát những gì xảy ra tiếp theo.


1
Tôi đồng ý với điều này. Có vấn đề về trình duyệt hiển thị thông báo cảnh báo về các chứng chỉ không đáng tin cậy, nhưng nếu bạn chỉ cố gắng ngăn người dùng truy cập https: // <địa chỉ ip> để nhận serverd một chứng chỉ không hợp lệ cho một trong những vhost thực của bạn (không hợp lệ bởi vì tên máy chủ sẽ không khớp), tốt hơn hết là bạn nên cung cấp cho họ chứng chỉ giả tự ký không hợp lệ. Kiểu đó nói với họ "không có gì để xem ở đây, thậm chí không có chứng chỉ từ máy chủ khác".
Daniel F

2

Thêm một khối máy chủ bắt tất cả và trả về mã trạng thái 444. Nó báo cho nginx đóng kết nối trước khi gửi bất kỳ dữ liệu nào.

server {
    listen 443 default_server ssl;
    server_name _;
    return 444;
}

1

Ngày nay, bạn có thể sử dụng tiện ích mở rộng Chỉ định Tên Máy chủ TLS (SNI, RFC 6066). Người nghe HTTPS sẽ có thể nhận ra tên miền trước khi cung cấp chứng chỉ phù hợp.

Điều này có nghĩa là bạn sẽ cần phải có chứng chỉ cho TẤT CẢ tên miền của mình và khi SNI được sử dụng để nhận ra một trong những tên miền khác, bạn chỉ có thể sử dụng chuyển hướng HTTP 301 sang phiên bản không được mã hóa HTTP trừ khi tên máy chủ khớp với tên miền duy nhất cần mã hóa.

Thông tin thêm về SNI có sẵn trong tài liệu nginx http://nginx.org/en/docs/http/configuring_https_servers.html


0

Ánh xạ tên máy chủ được yêu cầu đến tên máy chủ hợp lệ trong http {}khối:

map $ssl_server_name $correct_hostname_example {
  default 0;
  example.com 1;
  www.example.com 1;
}

Và sau đó, trong server {}khối chặn kết nối với tên máy chủ sai:

if ($correct_hostname_example = 0) {
  return 444;
}

Sử dụng nhiều bản đồ khi cần thiết cho nhiều khối máy chủ. Kết nối sẽ vẫn được thiết lập bằng một trong các chứng chỉ của bạn nhưng nếu khối cuối cùng này có mặt trong mọi khối máy chủ phục vụ SSL thì bạn sẽ "chặn" các kết nối với tên máy chủ không hợp lệ. Nó có thể chỉ cần thiết trong khối máy chủ đầu tiên nhưng thêm nó vào mọi khối máy chủ sẽ đảm bảo rằng thứ tự không thành vấn đề.

Các $ssl_server_namebiến có mặt trong nginx 1,7 hoặc cao hơn.


0

Đây là cách tôi giải quyết vấn đề:

  1. Tạo chứng chỉ tự ký:

openssl req -nodes -x509 -newkey rsa:4096 -keyout self_key.pem -out self_cert.pem -days 3650

  1. Sao chép nó ở nơi NginX có thể tìm thấy nó:

cp self*.pem /etc/nginx/ssl/

  1. Thiết lập lộ trình bắt tất cả:
server {
    listen 443 default_server ssl;

    ssl on;
    ssl_certificate /etc/nginx/ssl/self_cert.pem;
    ssl_certificate_key /etc/nginx/ssl/self_key.pem;

    return 301 http://$host;
}

Điều này sẽ làm gì: nó sẽ đưa ra cảnh báo (không có cách nào khác) trên bất kỳ máy chủ nào không có chứng chỉ riêng, nhưng cảnh báo sẽ không nói sai tên chứng chỉ. Nếu người dùng nhấp vào "truy cập bằng mọi cách", họ sẽ được chuyển hướng đến phiên bản không ssl của trang web họ đã nhập.

báo trước :

nếu trang web hỗ trợ SLL của bạn chỉ xác định www.example.com(và không example.com) thì tuyến bắt tất cả của bạn sẽ kết thúc phục vụ https://example.comvới chứng chỉ tự ký và cảnh báo tương ứng.


-2

Chuyển hướng đến http:

server {
    listen       443;
    server_name  *.com;
    rewrite        ^ http://$host$request_uri? permanent;
}    

Trả về 404

server {
    listen       443;
    server_name  *.com;
    return 404;
}    

1
Điều đó vẫn sẽ dẫn đến cảnh báo SSL, vì đường hầm SSL cần được thiết lập xảy ra trước khi bất kỳ chuyển hướng HTTP nào xảy ra. Xem câu trả lời được chấp nhận của David Schwartz.
cjc
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.