nginx: Cara mencegah blok server SSL yang benar-benar berfungsi sebagai catchall untuk semua SSL


17

Saya memiliki server web dengan banyak server virtual. Hanya 1 yang merupakan SSL. Masalahnya adalah, karena tidak ada blok server catchall yang mendengarkan SSL, setiap permintaan https ke situs lain dilayani oleh 1 blok SSL.

Konfigurasi saya, pada dasarnya, terlihat seperti ini:

# 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;
  # ...
}

Sekarang karena tidak ada pendengar default untuk 443, permintaan seperti https://server1.comakan berakhir dilayani oleh server2.comblok https. Ini mengikuti logika untuk server_namedalam dokumen.

Jika tidak ada kecocokan, blok server {...} di file konfigurasi akan digunakan berdasarkan urutan berikut:

  1. blok server dengan arahan mendengarkan yang cocok ditandai sebagai [default | default_server]
  2. blok server pertama dengan arahan mendengarkan yang cocok (atau mendengarkan secara implisit 80;)

Apa solusi yang disukai untuk masalah ini? Apakah saya perlu mengatur sertifikat dummy untuk tangkapan saya semua blok server supaya saya bisa mendengarkan 443 dan menangani permintaan yang buruk? Apakah ada parameter yang saya tidak tahu yang memaksa kecocokan hostname yang tepat dengan server?


Apa yang Anda inginkan terjadi ketika orang mencoba mengakses situs lain menggunakan https?
David Schwartz

Idealnya saya ingin nginx tidak melayani https sama sekali kecuali nama host cocok, atau untuk mengarahkan ulang ke http pada host yang sama.
numbers1311407

Jawaban:


9

Idealnya saya ingin nginx untuk tidak melayani https sama sekali kecuali nama host cocok, atau untuk mengarahkan ulang ke http pada host yang sama.

Tidak mungkin. Sambungan dari klien yang masuk ke https://foo.example.com/ tidak dapat diterima oleh apa pun kecuali sertifikat SSL dengan "foo.example.com" sebagai salah satu namanya. Tidak ada peluang untuk mengarahkan ulang sampai koneksi SSL diterima.

Jika Anda mengonfigurasi setiap situs untuk SSL, pengguna yang mengklik kesalahan sertifikat akan mendapatkan situs yang mereka minta. Jika Anda mengonfigurasi situs "tangkap semua" untuk SSL yang hanya menyediakan halaman kesalahan dan mengkonfigurasi hosting virtual berbasis nama untuk satu situs yang seharusnya mendukung SSL, Anda bisa melayani halaman kesalahan untuk klien.

Hosting virtual SSL dan HTTP tidak bisa bermain bersama dengan baik.


Inilah yang saya kumpulkan setelah membaca dokumen. Aku hanya berharap aku melewatkan sesuatu. Saya tidak peduli tentang peringatan SSL sama sekali. Saya hanya tidak ingin seseorang masuk ke server1.com dan mendapati diri mereka mencari di beranda server2.com ... Apakah benar-benar tidak ada cara untuk memberitahu nginx untuk tidak menerima permintaan?
numbers1311407

Jika tidak menerima permintaan, situs pertama tidak akan berfungsi. Itu harus menerima permintaan untuk mencari tahu situs apa yang coba diakses oleh pengguna.
David Schwartz

2
"Koneksi dari klien yang masuk ke foo.example.com tidak dapat diterima oleh apa pun kecuali sertifikat SSL dengan" foo.example.com "sebagai salah satu namanya." - Ini tidak benar, server akan menerima permintaan dan terserah klien untuk memverifikasi bahwa DN yang diminta cocok dengan sertifikat server DN.
ColinM

4

Satu-satunya cara adalah membuat sertifikat SSL yang ditandatangani sendiri dan menggunakannya untuk mendapatkan kontrol atas permintaan https yang masuk. Anda dapat membuat sertifikat SSL yang ditandatangani sendiri dalam beberapa langkah sederhana yang diuraikan dalam posting ini .

Katakanlah Anda membuat sertifikat yang ditandatangani sendiri dengan nama file server.crt. Anda kemudian akan menambahkan yang berikut ini di konfigurasi nginx Anda:

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;
}

Anda masih akan mendapatkan pesan peringatan SSL peramban, tetapi setidaknya Anda akan memiliki kendali atas apa yang terjadi selanjutnya.


1
Saya setuju dengan ini. Ada masalah pada peramban yang menampilkan pesan peringatan tentang sertifikat yang tidak dipercaya, tetapi jika Anda hanya berusaha mencegah pengguna masuk ke https: // <ip-address> untuk mendapatkan serverd sertifikat yang sama-sama tidak valid untuk salah satu vhost Anda yang sebenarnya (tidak valid karena nama inang tidak cocok), maka lebih baik Anda memberikan mereka sertifikat dummy yang ditandatangani sendiri yang tidak valid. Jenis mengatakan kepada mereka "tidak ada yang bisa dilihat di sini, bahkan sertifikat dari host lain".
Daniel F

2

Tambahkan catch-all server block dan kembalikan kode status 444. Ia memberi tahu nginx untuk menutup koneksi sebelum mengirim data apa pun.

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

1

Saat ini Anda dapat menggunakan ekstensi Indikasi Nama Server TLS (SNI, RFC 6066). Pendengar HTTPS akan dapat mengenali nama domain sebelum melayani sertifikat yang sesuai.

Ini berarti bahwa Anda harus memiliki sertifikat untuk SEMUA domain Anda, dan ketika SNI digunakan untuk mengenali salah satu domain lain, Anda bisa menggunakan HTTP 301 redirect ke HTTP versi non-terenkripsi kecuali nama server cocok dengan satu yang membutuhkan enkripsi.

Informasi lebih lanjut tentang SNI tersedia di dokumentasi nginx http://nginx.org/en/docs/http/configuring_https_servers.html


0

Petakan nama host yang diminta untuk nama host yang valid di http {}blok:

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

Dan kemudian di server {}blok itu, hentikan koneksi dengan nama host yang salah:

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

Gunakan beberapa peta seperlunya untuk beberapa blok server. Koneksi masih akan dibuat menggunakan salah satu sertifikat Anda tetapi jika blok terakhir ini hadir di setiap blok server yang melayani SSL maka secara efektif Anda akan "memblokir" koneksi dengan nama host yang tidak valid. Mungkin hanya diperlukan di blok server pertama tetapi menambahkannya ke setiap blok server akan memastikan bahwa pesanan tidak masalah.

The $ssl_server_namevariabel hadir dalam nginx 1,7 atau lebih besar.


0

Inilah cara saya memecahkan masalah:

  1. Buat sertifikat yang ditandatangani sendiri:

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

  1. Salin di tempat NginX dapat menemukannya:

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

  1. Siapkan rute tangkap semua:
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;
}

Apa yang akan dilakukan: ia akan memberi Anda peringatan (tidak ada jalan lain) di server mana pun yang tidak memiliki sertifikat sendiri, tetapi peringatan itu tidak akan menyebutkan nama sertifikat yang salah. Jika pengguna mengklik "kunjungi pula" mereka akan diarahkan ke versi non-ssl dari situs yang mereka ketikkan.

peringatan :

jika situs Anda yang mengaktifkan SLL hanya menentukan www.example.com(dan tidak example.com) maka rute tangkap-semua Anda akan berakhir https://example.comdengan sertifikat yang ditandatangani sendiri dan peringatan yang sesuai.


-2

Redirect ke http:

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

Return 404 :

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

1
Itu masih akan menghasilkan peringatan SSL, karena terowongan SSL perlu dibuat terjadi sebelum redirect HTTP akan terjadi. Lihat jawaban yang diterima David Schwartz.
cjc
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.