Apache Tidak Akan Meminta Sertifikat Klien SSL Saya

Pertama, harap dicatat bahwa saya baru dalam mengkonfigurasi SSL. Di masa lalu, saya selalu beruntung memiliki departemen TI yang menyiapkannya untuk saya sebelumnya. Jadi bersiaplah untuk kemungkinan bahwa saya mungkin perlu meminta klarifikasi atas beberapa jawaban Anda. =)

Apa yang Saya Coba Lakukan

Saya sedang menyiapkan situs web intranet perusahaan untuk karyawan. Misalnya, akan ada halaman awal browser yang menampilkan konten yang disesuaikan untuk setiap karyawan. Oleh karena itu, saya harus dapat mengidentifikasi karyawan tersebut tanpa memerlukan nama pengguna/kata sandi atau perintah lainnya (meskipun pengaturan satu kali tidak masalah; saya hanya tidak ingin mereka diminta setiap saat). Tentu saja, SSL tampaknya menjadi cara terbaik untuk melakukan hal ini.

Saya akan menyiapkan database MySQL untuk mengaitkan akun "pengguna" dengan SSL_CLIENT_M_SERIAL dan SSL_CLIENT_I_DN, yang saya asumsikan akan unik untuk setiap sertifikat klien (?). Saya mendapat ide itu dari artikel ini: http://cweiske.de/tagebuch/ssl-client-certificates.htm

Pertama kali pengguna mengunjungi situs web internal, mereka tidak akan memiliki sertifikat (saya TIDAK ingin membuatnya secara manual untuk klien!), dalam hal ini $_SERVER["SSL_CLIENT_VERIFY"] == "NONE". Jika itu terjadi, maka akan masuk ke halaman pengaturan akun pengguna, yang akan mencakup langkah di mana PHP menghasilkan sertifikat klien SSL dan mengirimkannya ke browser untuk dipasang oleh pengguna. Bagus dan sederhana. Pengguna kemudian menginstal sertifikat, pengaitan dibuat, dan setelah memulai ulang browser (sebagai tambahan), pengguna kembali ke situs web internal.

Pada titik ini, Apache harus meminta sertifikat klien, yang kemudian dikirimkan oleh browser. Skrip PHP kemudian mem-parsing variabel $_SERVER yang diperlukan, membandingkannya dengan database MySQL, dan saat-saat yang menyenangkan telah dinikmati semua orang. Sekali lagi, bagus dan sederhana.

Apa yang Berhasil Sejauh Ini

Saya telah menginstal sertifikat sisi server. Dan ya, itu ditandatangani sendiri (untuk alasan yang jelas). Apache telah menginstal mod_ssl dan semuanya tampaknya berfungsi dengan baik. Saya membuat skrip PHP yang hanya membuang array $_SERVER, dan semua nilai kunci SSL_SERVER_* cocok dengan sertifikat yang saya buat untuk itu.

Masalahnya

Saya tidak bisa membuat sertifikat klien berfungsi! Dalam skrip PHP yang sama, apa pun yang saya lakukan, SSL_CLIENT_VERIFY == "NONE" dan kunci SSL_CLIENT_* lainnya hilang. Inilah yang terjadi jika saya menyetel SSLVerifyClient ke opsional di ssl.conf. Menurut setiap tutorial yang saya baca, semuanya mengatakan bahwa server web harus meminta sertifikat klien kepada browser. Masalahnya, saya tidak bisa melakukan itu! Itu langsung ke skrip PHP dan berasumsi saya tidak memiliki sertifikat klien sama sekali. Ini terjadi di Firefox, Chrome, dan IE.

Jadi saya mencoba menyetel SSLVerifyClient ke wajib dan memulai ulang server web. Dengan adanya opsi itu, saya bahkan tidak dapat membuat koneksi SSL. Firefox hanya mengatakan bahwa koneksi telah disetel ulang (browser lain juga menampilkan versi kesalahannya sendiri). Yang aneh adalah log tidak menunjukkan aktivitas APAPUN pada upaya koneksi ini! Yaitu. access_log, error_log, ssl_access_log, ssl_error_log, DAN ssl_request_log semuanya tidak menampilkan APA SAJA; seolah-olah upaya itu tidak pernah terjadi. Ini membuat frustrasi karena itu berarti saya bahkan tidak mempunyai pesan kesalahan untuk digunakan. Hanya server web yang pasif-agresif menyuruh saya pergi ke neraka.

Saya mencoba membuat/menginstal sertifikat klien saya sendiri secara manual menggunakan ekstensi OpenSSL PHP. Sertifikat terinstal dengan baik, meskipun saya tidak dapat menemukan informasi apa pun tentang cara mengaitkan sertifikat itu dengan server (dengan asumsi saya perlu melakukannya?). Selain itu, tampaknya hal itu tidak menjadi masalah, karena Apache tetap tidak akan meminta sertifikat klien jika opsional disetel. Dan jika require disetel, itu akan meledak tanpa penjelasan. Saya tetap membutuhkannya untuk disetel ke opsional agar skema ini berfungsi.

Lingkungan

OS: CentOS 5.7 64-bit (Kotak Virtual)

Apache: 2.2.3

PHP: 5.3.10

Saya kira Anda mungkin memerlukan info lebih lanjut untuk membantu saya, jadi silakan bertanya! Saya akan menyediakan apa pun yang Anda butuhkan.

Singkatnya, saya perlu mengetahui cara membuat Apache meminta sertifikat klien SSL dengan mempertimbangkan ketentuan yang diuraikan di atas. Selain itu, jika ada penandatanganan khusus/dll yang harus dilakukan untuk membuat sertifikat klien "kompatibel" dengan sertifikat server (sekali lagi, TANPA melakukannya secara manual melalui Shell untuk setiap sertifikat klien!), Saya perlu mengetahuinya sebagai Sehat.

Saya 100% terjebak dalam hal ini sampai sekarang. Tidak dapat menemukan apa pun yang bermanfaat bahkan dari jarak jauh di Google. Bantuan apa pun yang dapat Anda berikan mengenai hal ini akan SANGAT dihargai!! Terima kasih! =)


person Kris Craig    schedule 20.04.2012    source sumber
comment
Apakah setiap sertifikat klien yang dihasilkan ditandatangani sendiri? Atau apakah Anda membuat CA sendiri untuk menandatangani permintaan yang dihasilkan? Klien hanya akan meminta Anda untuk memberikan sertifikat jika Anda memiliki sertifikat terinstal yang ditandatangani dari otoritas tepercaya (yang ditentukan oleh penyimpanan kepercayaan server). Jika setiap sertifikat klien ditandatangani sendiri, Anda memerlukan setiap sertifikat yang dihasilkan berada di penyimpanan kepercayaan server, yang tidak mungkin dilakukan.   -  person bobz32    schedule 21.04.2012
comment
Saya mencoba membuat sertifikat klien di server menggunakan openssl, mengekspor sebagai p12, lalu menginstalnya di Firefox, tetapi sekarang saya mendapatkan kesalahan tidak bisa mendapatkan sertifikat penerbit lokal dari Apache. Saya menandatangani sertifikat klien menggunakan sertifikat server, jadi mengapa tidak berfungsi? Saya mencoba menghapus komentar pada baris SSLCACertificateFile di ssl.conf, tapi kemudian itu mengembalikan saya ke masalah pertama, yaitu halaman dimuat dengan baik tetapi tanpa mengenali sertifikat klien. Jadi sekali lagi saya kembali ke titik awal....   -  person Kris Craig    schedule 21.04.2012


Jawaban (3)


Pertama, Anda perlu mengkonfigurasi Apache Httpd untuk meminta sertifikat klien. Untuk ini, Anda setidaknya perlu menggunakan SSLVerifyClient optional pada lokasi/direktori yang ingin Anda autentikasi dengan metode ini.

Kedua, sertifikat yang dikirim oleh klien juga harus dipercaya oleh Apache Httpd. (Pada prinsipnya Anda dapat menggunakan SSLVerifyClient optional_no_ca, membiarkan klien mana pun melakukan sertifikasi di tumpukan Apache Httpd SSL/TLS, dan baru kemudian memverifikasi sertifikat dalam PHP, tetapi itu cukup merepotkan, sehingga Anda perlu lebih berhati-hati karena itu belum tentu kode yang mudah; yang lebih penting, ini akan sangat tidak berguna dalam konteks ini, karena Anda berada dalam skenario di mana Anda mengendalikan CA Anda.)

Sejauh yang saya pahami, SSL_CLIENT_VERIFY (variabel yang saya sendiri jarang gunakan) sepertinya hanya berguna dengan SSLVerifyClient optional_no_ca. Ini mungkin berhasil dengan SSLVerifyClient optional, tapi saya ragu. SSLVerifyClient require akan menolak koneksi menggunakan sertifikat klien yang tidak dipercaya (oleh salah satu CA di SSLCACertificateFile/SSLCACertificatePath), atau jika tidak ada sertifikat. Sejauh yang saya tahu, SSLVerifyClient optional akan membiarkan klien lewat tanpa sertifikat atau dengan sertifikat tepercaya, tetapi juga akan menolak koneksi jika sertifikat tidak dipercaya.

Di sini, dengan menolak koneksi, maksud saya menutup koneksi SSL/TLS secara tiba-tiba dengan peringatan. Tidak ada kemungkinan untuk menghasilkan halaman kesalahan HTTP(S). Semua yang Anda dapatkan adalah kesalahan browser standar, seperti ssl_error_unknown_certificate_.... (Anda harus mempertimbangkan hal ini dalam hal kegunaan.)

Sejak saat itu, yang Anda perlukan adalah menyiapkan CA Anda sendiri, mungkin berbasis web dengan pembuatan kunci dalam browser dan dalam situs web yang sama. Anda tidak ingin SSLVerifyClient require untuk itu, karena Anda harus mengizinkan pengguna yang belum memiliki sertifikat (gunakan optional sebagai gantinya). Meskipun demikian, arahan ini tidak perlu berlaku untuk seluruh host, namun dapat spesifik untuk lokasi/direktori tertentu.

Mengintegrasikan CA berbasis web Anda sendiri (atau lebih umum lagi, membuat CA Anda sendiri) tidak selalu mudah jika Anda baru mengenal semua ini. Ada alat siap pakai (misalnya OpenCA), atau Anda dapat membuatnya sendiri menggunakan berbagai bagian JavaScript/ActiveX, dan Anda akan melakukannya memerlukan kode sisi server untuk menangani permintaan SPKAC atau PKCS#10 (dan untuk menerbitkan sertifikat sebenarnya). (Agar CA tersebut berguna, Anda ingin pengguna yang mengajukan permohonan sertifikat baru memberikan beberapa bukti ID pada saat mengajukan permohonan, mungkin kata sandi.)

Saat ini sudah disiapkan, Anda harus mengonfigurasi SSLCACertificateFile (atau ...Path) agar menunjuk ke sertifikat CA dari CA internal Anda (apakah itu CA berbasis web atau bukan, di situs yang sama atau tidak). (Tentu saja, jagalah kunci pribadi CA Anda tetap pribadi, mungkin dikonfigurasi dalam aplikasi berbasis web CA Anda, namun Apache Httpd sendiri tidak perlu mengetahuinya.) Browser hanya akan menyarankan sertifikat yang dikeluarkan oleh CA atau perantara tersebut (kecuali Anda juga telah mengonfigurasi SSLCADNRequestFile, yang akan digunakan untuk mengirim daftar CA yang diterima).

Perhatikan bahwa kedua langkah ini (menyiapkan CA Anda dan menyiapkan situs web Anda untuk menggunakan sertifikat klien) sebenarnya bersifat independen. Fakta bahwa keduanya dapat menjadi bagian dari situs yang sama dapat memudahkan, namun tidak diperlukan. Anda dapat mencoba pengaturan Apache Httpd tanpa menerapkan seluruh CA di situs terlebih dahulu (saya akan merekomendasikan hal itu, meskipun itu hanya untuk melihat apa yang Anda hadapi). Ada sejumlah alat untuk membuat CA kecil Anda sendiri yang dapat dikelola dengan beberapa sertifikat: CA.pl OpenSSL atau TinyCA misalnya. Anda juga dapat menggunakan sertifikat pengujian (localhost dan testclient, testclient_r dicabut jika Anda ingin menggunakan CRL, mungkin tidak diperlukan pada awalnya): semua sandi adalah testtest.

Seperti yang sudah Anda perkirakan (dengan DB MySQL Anda), Anda harus mengelola sertifikat yang Anda terbitkan dan memetakannya ke pengguna. SSL_CLIENT_M_SERIAL dan SSL_CLIENT_I_DN bukanlah variabel yang tepat untuk digunakan. SSL_CLIENT_I_DN adalah DN Penerbit (yaitu DN Subjek CA). Apa yang Anda cari adalah SSL_CLIENT_S_DN: DN Subjek sertifikat klien. SSL_CLIENT_M_SERIAL adalah nomor seri sertifikat: jangan gunakan, karena unik untuk setiap sertifikat: satu pengguna dapat memiliki beberapa sertifikat dengan DN Subjek yang sama (misal, jika ada yang kedaluwarsa atau dicabut).


Terlepas dari semua ini, saya tidak yakin apakah sertifikat klien adalah cara terbaik untuk mencapai tujuan Anda (membiarkan karyawan di perusahaan Anda masuk tanpa kata sandi).

  • Pertama, pengguna tetap harus melindungi sertifikat mereka sendiri dengan kata sandi. Saya kira, yang sebenarnya Anda cari adalah suatu bentuk Sistem Masuk Tunggal (SSO).

  • Kedua, tergantung pada tingkat kemampuan komputer pengguna Anda, sertifikat sebenarnya bisa jadi cukup sulit untuk dikelola.

    Fakta bahwa kata "sertifikat", sebenarnya, tidak menyertakan kunci privat sama sekali, namun terkadang menyiratkan penggunaan kunci privat dapat membingungkan bagi sebagian orang. Di satu sisi, terkadang Anda mendengar "Impor sertifikat Anda ke browser Anda" dan "Gunakan sertifikat Anda untuk masuk"; di sisi lain, Anda juga dapat mendengar "kirimkan saya sertifikat Anda". Yang pertama menyiratkan penggunaan dan ketersediaan kunci pribadi ("sertifikat" mungkin berarti .p12 dalam ekspresi ini). Yang terakhir pastinya tidak melibatkan kunci pribadi.

    Antarmuka pengguna browser cenderung buruk atau membingungkan untuk mengelola sertifikat atau keluar. Sekali lagi, jika sertifikat tidak dikenali, koneksi SSL/TLS tidak akan dibuat, sehingga server web tidak berkesempatan menampilkan halaman kesalahan HTML apa pun.

Mungkin Anda juga dapat mempertimbangkan bentuk SSO lainnya (misalnya CAS, berbasis SAML atau Kerberos/SPNEGO.)

person Bruno    schedule 21.04.2012

Saya memiliki masalah serupa dengan:

  • CentOS 6.3
  • Apache 2.2.15

Setelah beberapa kali mencoba saya menyadari masalah saya.

Jika saya menetapkan SSLVerifyClient optional atau SSLVerifyClient optional_no_ca dan saya menentukan juga SSLCACertificateFile atau SSLCACertificatePath, Apache memperoleh sertifikat klien hanya jika dilepaskan dari CA yang ditemukan di file/jalur referensi CA yang ditentukan dalam konfigurasi.

person lgaggini    schedule 25.01.2013

Anda dapat melihat dokumen Apache jika belum selesai.

Prinsip umumnya adalah Anda membuat sertifikat yang ditandatangani sendiri dan memeriksanya sebelum mencoba menggunakannya.

Kemudian sepertinya klien terhubung ke situs intranet Anda melalui http. Dari sana, ada banyak cara berbeda untuk beralih ke https menggunakan sertifikat SSL Anda. Cara termudah adalah dengan menggunakan modul penulisan ulang Apache. Namun dalam kasus Anda, saat Anda melakukan pemeriksaan php/mysql, Anda dapat mengalihkan klien Anda dari http ke ke https, dan ini bukan cara yang sederhana.

Dalam kedua kasus tersebut (pengalihan otomatis Apache melalui mod_rewrite, atau pengalihan dengan tes berjenjang (php/javascript/html), Anda perlu mengatur 2 vhost Anda (satu untuk http dan satu untuk https) dengan cara yang benar, tetapi ini mengasumsikan beberapa hipotesis.

Misalnya (debian - Apache 2.2), berikut adalah pengalihan otomatis, yang dilakukan oleh Apache (misalnya kasus pertama dijelaskan di atas):

cat /etc/Apache2/sites-available/test

# VHOST test

<VirtualHost *:80>

    DocumentRoot /home/www/test
    ServerName www.test.dev

    # ######################
    # Redirect commons
    # ######################
    RewriteEngine on
    # Case of vhosts
    RewriteOptions Inherit

    # ######################
    # Redirect (empty index)
    # ######################

    # Condition 1 to redirect : request matching with the server
    RewriteCond %{HTTP_HOST}   ^www\.test\.dev [NC]

    # Condition 2 to redirect : non empty HOST
    RewriteCond %{HTTP_HOST}   !^$

    # Automatic Empty requests Redirect
    RewriteRule ^(.*)/$ /index.php


    # ######################
    # Redirect to SSL
    # ######################
    RewriteCond %{HTTP_HOST}   ^www\.test\.dev [NC]
    RewriteCond %{HTTP_HOST}   !^$
    RewriteCond %{SERVER_PORT} ^80$
    RewriteCond %{REQUEST_URI} /

    # Redirection
    RewriteRule ^/(.*)$ https://%{SERVER_NAME}%{REQUEST_URI} [L,R]

</VirtualHost>

Host virtual kedua untuk SSL: cat /etc/Apache2/sites-available/test-ssl

# VHOST for ssl

DocumentRoot "/home/www/test"
ServerName www.test.dev

    # SSL
    SSLEngine on
    SSLCACertificateFile /etc/apache2/ssl/cur_cert/ca.pem
    SSLCertificateFile /etc/apache2/ssl/cur_cert/serveur.pem
    SSLCertificateKeyFile /etc/apache2/ssl/cur_cert/serveur.key


    <Directory "/home/www/test">
        Options FollowSymLinks MultiViews
        AllowOverride None
        Order allow,deny
        Allow from 127.0.0.1 192.168.0.0/16
    </Directory>


    <Directory "/home/www/test/cgi-bin">
        Options FollowSymLinks MultiViews
        AllowOverride None
        Order allow,deny
        Allow from 127.0.0.1 192.168.0.0/16
        Options +ExecCGI
        AddHandler cgi-script .cgi
    </Directory>

</VirtualHost>

Your case might defer slightly from this, eg you will not have the redirect portion in the 1st vhost, but only a simple vhost and the second one for https (ssl). The redirection will be done by php/javascript once you have achieved your mysql checks.

Berikut adalah contoh abstrak dari kelas php untuk cara melakukan cascade peralihan dari http ke https, menggunakan php, lalu javascript, lalu html :

public function Redirect($url){

    if (TRUE !== Validator::isValidURL($url))
        die ("FATAL ERR: url not valid");

    // PHP ABSOLUTE URL REDIRECT (HTTP1.1)
    if (!headers_sent()) {

        header("Status: 200");
        header("Cache-Control: no-cache, must-revalidate"); // required for HTTP/1.1
        header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // past Date
        header("Pragma: no-cache");
        header('Location: '.$url); // note: 302 code return by default with "Location"
        flush();
        exit();

        // if headers are already sent... do javascript redirect... if javascript is disabled, do html redirect.
    } else {

        // Js redirect
        echo '<script type="text/javascript">';
        //echo "<!--";
        echo 'document.location="'. $url .'";';
        //echo "//-->";
        echo '</script>';

        // HTML redirect if js disabled
        echo '<noscript>';
        echo '<meta http-equiv="refresh" content="0;url="'.$url.'" />';
        echo '</noscript>';

        exit();
    }

    return FALSE;

} /* end of method (redirect) */

Semoga ini bisa membantu Anda untuk lebih memahami cara melanjutkan dan menyesuaikan pendekatan ini dengan kasus spesifik Anda.

person hornetbzz    schedule 20.04.2012
comment
Namun masalah yang saya alami bukan terkait pengalihan. Saya mengakses halaman secara langsung melalui https. Yaitu. di browser, saya menggunakan https://. Jadi port 80 tidak menjadi masalah. - person Kris Craig; 21.04.2012
comment
Saya mencoba membuat sertifikat klien di server menggunakan openssl, mengekspor sebagai p12, lalu menginstalnya di Firefox, tetapi sekarang saya mendapatkan kesalahan tidak bisa mendapatkan sertifikat penerbit lokal dari Apache. Saya menandatangani sertifikat klien menggunakan sertifikat server, jadi mengapa tidak berfungsi? Saya mencoba menghapus komentar pada baris SSLCACertificateFile di ssl.conf, tapi kemudian itu mengembalikan saya ke masalah pertama, yaitu halaman dimuat dengan baik tetapi tanpa mengenali sertifikat klien. - person Kris Craig; 21.04.2012
comment
Maaf, saya lebih memahami maksud Anda sekarang dan tidak memiliki solusi sederhana lain selain menghubungkan http dan mengganti https setelah pemeriksaan mysql dilakukan setelah login, yang menurut saya merupakan pendekatan yang lebih aman tetapi merupakan kode yang cukup besar menurut pengalaman konsumen. - person hornetbzz; 21.04.2012
comment
Ini tidak ada hubungannya dengan pertanyaan itu. - person paf.goncalves; 19.06.2014