Requests: Tentukan kata sandi untuk sertifikat sisi klien SSL

Dibuat pada 3 Sep 2013  ·  121Komentar  ·  Sumber: psf/requests

Sejauh yang saya tahu saat ini tidak mungkin untuk menentukan kata sandi untuk sertifikat sisi klien yang Anda gunakan untuk otentikasi.
Ini sedikit masalah karena Anda biasanya selalu ingin melindungi file .pem Anda dengan kata sandi yang berisi kunci pribadi. openssl bahkan tidak akan membiarkan Anda membuatnya tanpa kata sandi.

Documentation Planned

Komentar yang paling membantu

@botondus Saya pikir saya menemukan cara yang lebih sederhana untuk mencapai ini dengan perpustakaan permintaan. Saya mendokumentasikan ini untuk orang lain yang menghadapi masalah ini.

Saya berasumsi bahwa Anda memiliki sertifikat .p12 dan frasa sandi untuk kuncinya.

Hasilkan sertifikat dan kunci pribadi.

// Generate the certificate file.
openssl pkcs12 -in /path/to/p12cert -nokeys -out certificate.pem
// Generate private key with passpharse, First enter the password provided with the key and then an arbitrary PEM password //(say: 1234) 
openssl pkcs12 -in /path/to/p12cert -nocerts -out privkey.pem

Yah, kita belum selesai dan kita perlu membuat kunci yang tidak memerlukan kata sandi PEM setiap kali perlu berbicara dengan server.

Hasilkan kunci tanpa frasa sandi.

// Running this command will prompt for the pem password(1234), on providing which we will obtain the plainkey.pem
openssl rsa -in privkey.pem -out plainkey.pem

Sekarang, Anda akan memiliki certificate.pem dan plainkey.pem , kedua file yang diperlukan untuk berbicara dengan API menggunakan permintaan.

Berikut adalah contoh permintaan menggunakan sertifikat dan kunci ini.

import requests
url = 'https://exampleurl.com'
headers = {
            'header1': '1214141414',
            'header2': 'adad-1223-122'
          }
response = requests.get(url, headers=headers, cert=('~/certificate.pem', '~/plainkey.pem'), verify=True)
print response.json()

Semoga ini membantu:

cc @kennethreitz @Lukasa @sigmavirus24

Semua 121 komentar

Sesuatu seperti:

requests.get('https://kennethreitz.com', cert='server.pem', cert_pw='my_password')

Cukup yakin Anda seharusnya menggunakan param cert untuk itu: cert=('server.pem', 'my_password')

@sigmavirus24
Tuple adalah untuk (certificate, key) . Saat ini tidak ada dukungan untuk file kunci terenkripsi.
Stdlib hanya mendapat dukungan untuk versi 3.3.

Heh, @t-8ch, Anda tidak sengaja menautkan ke file di FS lokal Anda. ;) Tautan yang benar .

Benar sekali @t-8ch. Inilah sebabnya mengapa saya tidak boleh menjawab masalah dari bus. :/

Jadi konsensus saat ini adalah kami tidak mendukung ini. Berapa banyak pekerjaan yang mungkin dilakukan untuk menambahkan dukungan di Python versi non-3.3?

Seberapa sulitkah untuk membuat kesalahan pada kondisi ini? Saya baru saja mengalami masalah konyol ini dan butuh dua jam untuk mencari tahu, alangkah baiknya jika itu akan menimbulkan kesalahan, saat ini hanya duduk di sana berulang-ulang. Terima kasih untuk perpustakaan yang luar biasa!

Tunggu, itu duduk di mana perulangan? Di mana dalam eksekusi kita gagal? Bisakah Anda mencetak traceback dari tempat kita mengulang?

Tampaknya menggantung di sini:

r = permintaan.get(url,
auth=headeroauth,
cert=self.cert_tuple,
tajuk = tajuk,
batas waktu=10,
verifikasi=Benar)

Saya mencoba mengubah batas waktu naik atau turun tetapi tidak berhasil, tetapi saya membayangkan itu tahu dengan baik sebelum batas waktu itu tidak dapat menggunakan sertifikat. Terima kasih!

Ah, maaf, saya tidak jelas. Saya bermaksud membiarkannya menggantung dan kemudian membunuhnya dengan Ctrl + C sehingga python melempar pengecualian KeyboardInterrupt, lalu untuk melihat di mana kita berada di traceback. Saya ingin tahu di mana di Permintaan eksekusi berhenti.

Apa yang terjadi (atau setidaknya apa yang saya lihat dalam banyak kasus) adalah bahwa OpenSSL, setelah diberikan sertifikat yang dilindungi kata sandi, akan meminta kata sandi kepada pengguna. Itu muncul tanpa log (karena prompt langsung dicetak), dan tidak time out karena menunggu pengguna untuk menekan enter.

Tak perlu dikatakan, itu rumit, perilaku berbahaya ketika kode berjalan di server (karena itu akan menggantung pekerja Anda tanpa pilihan untuk pemulihan selain mematikan proses).

Apakah ada cara untuk membuat permintaan memunculkan pengecualian dalam kasus itu alih-alih meminta kata sandi, atau apakah itu sepenuhnya di luar kendali Anda dan di tangan OpenSSL?

@maxnoel Saya cukup yakin ini ada di tangan OpenSSL tetapi jika Anda dapat menjawab pertanyaan @Lukasa (komentar terakhir tentang masalah ini) akan sangat membantu dalam memberikan jawaban yang pasti mengenai apakah ada yang bisa kami lakukan untuk membantu .

Anda dapat mengonfirmasi bahwa OpenSSL memblokir stdin untuk frasa sandi dari prompt python interaktif:

>>> r = requests.get("https://foo.example.com/api/user/bill", cert=("client.crt", "client.key"))
Enter PEM pass phrase:
>>>

Jika Anda menjalankan dari proses latar belakang, saya berasumsi OpenSSL akan memblokir menunggu input itu.

Itu benar. Apakah ada yang bisa dilakukan permintaan untuk mencegah hal itu terjadi? Meningkatkan pengecualian ketika tidak ada kata sandi yang diberikan akan jauh lebih berguna daripada meminta hal-hal di stdin (terutama dalam program non-interaktif).

Saya khawatir saya tidak tahu cara apa pun. @reaperhulk?

Ada beberapa cara untuk menghentikan OpenSSL melakukan ini, tetapi saya tidak yakin apakah mereka diekspos oleh pyOpenSSL. Di mana permintaan memanggil pyopenssl untuk memuat sertifikat klien? Saya bisa menggali sedikit.

@reaperhulk Sudah selesai dari di urllib3, di sini .

Kami juga melakukan sesuatu yang sangat mirip untuk stdlib, yang akan menjadi masalah terpisah.

Jadi kita bisa melakukan ini dengan PyOpenSSL menggunakan patch seperti ini . Dalam versi stdlib, kita perlu menggunakan load_cert_chain dengan kata sandi.

Apakah masalah ini sudah terpecahkan? Saat ini saya mengalami ini ketika mencoba terhubung ke server Apache.

Tidak.

Bagaimana dengan wadah yang diformat (dan dienkripsi) PKCS#12 yang dapat berisi sertifikat/kunci klien? Apakah ini termasuk dalam permintaan fitur yang sama?

@mikelupo ya .

@telam @mikelupo
Saya memiliki masalah yang sama dan banyak mencari di Google, akhirnya, saya menyelesaikannya dengan menggunakan pycurl.
Dalam situasi saya, saya menggunakan openssl untuk mengonversi file .pfx saya menjadi file .pem yang berisi sertifikat & kunci (dienkripsi dengan frasa sandi), lalu jalankan kode berikut.

import pycurl
import StringIO

b = StringIO.StringIO()
c = pycurl.Curl()
url = "https://example.com"
c.setopt(pycurl.URL, url)
c.setopt(pycurl.WRITEFUNCTION, b.write)
c.setopt(pycurl.CAINFO, "/path/cacert.pem")
c.setopt(pycurl.SSLKEY, "/path/key_file.pem")
c.setopt(pycurl.SSLCERT, "/path/cert_file.pem")
c.setopt(pycurl.SSLKEYPASSWD, "your pass phrase")
c.perform()
c.close()
response_body = b.getvalue()

BTW, untuk keamanan, lebih baik tidak melakukan hardcode untuk pass phrase

Tentu saja. Meskipun demikian, masalahnya bukanlah frasa sandi yang diperlukan -- melainkan OpenSSL yang membuat program Anda hang saat menunggu seseorang mengetikkan frasa sandi di stdin, bahkan dalam kasus program non-interaktif, GUI, atau jarak jauh.

Ketika frasa sandi diperlukan dan tidak ada yang diberikan, pengecualian harus dimunculkan sebagai gantinya.

jika Anda menggunakan frasa sandi default '' untuk kuncinya, openssl tidak akan hang.
itu akan mengembalikan teks kata sandi yang buruk. Anda dapat segera mengubah aliran py Anda
untuk kemudian memberi tahu pengguna tanpa kios yang terlihat

ada rencana untuk menambahkan fitur ini

Kami ingin menambahkannya, tetapi kami tidak memiliki jadwal untuk menambahkannya saat ini.

@botondus Saya pikir saya menemukan cara yang lebih sederhana untuk mencapai ini dengan perpustakaan permintaan. Saya mendokumentasikan ini untuk orang lain yang menghadapi masalah ini.

Saya berasumsi bahwa Anda memiliki sertifikat .p12 dan frasa sandi untuk kuncinya.

Hasilkan sertifikat dan kunci pribadi.

// Generate the certificate file.
openssl pkcs12 -in /path/to/p12cert -nokeys -out certificate.pem
// Generate private key with passpharse, First enter the password provided with the key and then an arbitrary PEM password //(say: 1234) 
openssl pkcs12 -in /path/to/p12cert -nocerts -out privkey.pem

Yah, kita belum selesai dan kita perlu membuat kunci yang tidak memerlukan kata sandi PEM setiap kali perlu berbicara dengan server.

Hasilkan kunci tanpa frasa sandi.

// Running this command will prompt for the pem password(1234), on providing which we will obtain the plainkey.pem
openssl rsa -in privkey.pem -out plainkey.pem

Sekarang, Anda akan memiliki certificate.pem dan plainkey.pem , kedua file yang diperlukan untuk berbicara dengan API menggunakan permintaan.

Berikut adalah contoh permintaan menggunakan sertifikat dan kunci ini.

import requests
url = 'https://exampleurl.com'
headers = {
            'header1': '1214141414',
            'header2': 'adad-1223-122'
          }
response = requests.get(url, headers=headers, cert=('~/certificate.pem', '~/plainkey.pem'), verify=True)
print response.json()

Semoga ini membantu:

cc @kennethreitz @Lukasa @sigmavirus24

Saya telah mendengar melalui selentingan bahwa Amazon melakukan hal ini, secara internal.

Saya menghadapi masalah ini juga. Kekhawatiran saya adalah saya tidak ingin menyimpan kunci pribadi biasa ke sistem file (Mungkin berisiko dicuri oleh orang lain). Jadi menurut saya, cara yang lebih dapat diperluas untuk mengimplementasikan ini adalah dengan mendukung penggunaan sesuatu seperti PEM encoded string of private key alih-alih jalur file untuk menentukan kunci pribadi. Baru saja menyerahkan enkripsi / dekripsi kunci pribadi / sertifikat kepada pengembang dengan cara yang menguntungkan mereka.
Setelah membaca kode sumber permintaan, tampaknya tidak cukup mudah untuk diterapkan karena permintaan bergantung pada ssl lib python yang hanya mendukung file sertifikat/kunci pribadi. Saya hanya ingin tahu apakah kita bisa menggunakan pyopenssl daripada python stdlib? pyopenssl memiliki pembungkus koneksi openssl, lihat: https://pyopenssl.readthedocs.io/en/latest/api/ssl.html#connection -objects . Dengan demikian kita dapat menggunakan objek 'pkey' sebagai kunci pribadi alih-alih jalur file.

Permintaan sudah mendukung PyOpenSSL, selama itu dan beberapa dependensi lain yang diperlukan diinstal. Namun, itu tidak akan pernah menjadi wajib: penting bagi kami bahwa kami bekerja dengan baik dengan perpustakaan standar.

Dalam rilis mendatang kami akan memiliki dukungan untuk meneruskan objek SSLContext ke urllib3 untuk menangani TLS: yang akan mengaktifkan fungsi ini.

Bagi mereka yang menghadapi masalah ini, hingga permintaan menambahkan kemampuan untuk meneruskan ssl.SSLContext/OpenSSL.SSL.Context ke urllib3, berikut adalah solusi yang benar-benar mendukung penggunaan sertifikat/file kunci terenkripsi (mengharuskan PyOpenSSL diinstal dan digunakan alih-alih pustaka standar ssl, yang seharusnya jika diinstal)

import requests

 # Get the password from the user/configfile/whatever
password = ...

# Subclass OpenSSL.SSL.Context to use a password callback that gives your password
class PasswordContext(requests.packages.urllib3.contrib.pyopenssl.OpenSSL.SSL.Context):
    def __init__(self, method):
        super(PasswordContext, self).__init__(method)
        def passwd_cb(maxlen, prompt_twice, userdata):
            return password if len(password) < maxlen else ''
        self.set_passwd_cb(passwd_cb)

# Monkey-patch the subclass into OpenSSL.SSL so it is used in place of the stock version
requests.packages.urllib3.contrib.pyopenssl.OpenSSL.SSL.Context = PasswordContext

# Use requests as normal, e.g.
endpoint = 'https://example.com/authenticated'
ca_certs = '/path/to/ca/certs/bundle'
certfile = '/path/to/certificate'
keyfile = '/path/to/encrypted/keyfile'
requests.get(endpoint, verify=ca_certs, cert=(certfile, keyfile))

@ahnolds : Apakah ini juga berfungsi untuk file PKCS#12, atau hanya PEM ini?

@Lukasa : Apakah kasus PKCS#12 benar-benar harus ditangani di sini, atau haruskah saya membuka masalah terpisah untuk itu?

PKCS#12 adalah masalah yang lebih rumit, tetapi pada dasarnya Anda harus melakukan apa pun yang diperlukan untuk menyesuaikan SSLContext Anda.

@Lukasa : Saya lebih berpikir untuk menyediakan API tingkat tinggi yang bagus dalam permintaan. Misalnya, cukup berikan nama file client_cert.p12 dan kata sandi melalui parameter kata kunci cert=... .

@vog Kode apa yang Anda yakini diperlukan untuk membuatnya berfungsi?

@Lukasa Saya tidak yakin tentang internal requests , jadi mungkin saya meremehkan apa yang sudah ada, tetapi saya pikir salah satu dari hal-hal berikut perlu dilakukan:

  • Entah kami memiliki cara untuk memberikan nama file PKCS#12 langsung ke lapisan bawah (urllib3, dll.). Dan mungkin juga kata sandinya. (Karena saya tidak tahu siapa pun yang menginginkan pustaka URL untuk meminta admin secara interaktif memasukkan kata sandi PKCS#12 mereka pada alat yang menjalankan sisi server.)
  • Jika itu tidak mungkin, kita perlu mengonversi PKCS#12 (+kata sandi) ke PEM, lalu memberikannya ke level yang lebih rendah. Ini dilakukan dengan beberapa panggilan langsung ke pengikatan OpenSSL . Namun, hasilnya adalah sertifikat PEM sebagai string, dan saya belum menemukan cara untuk menyediakan PEM (tidak terenkripsi) sebagai string ke lapisan bawah (kecuali mungkin dengan menggunakan pembungkus OpenSSL / python "ssl" "buffer", misalnya wrap_bio , tetapi ini hanya tersedia di versi Python 3 terbaru, bukan Python 2).
  • Jadi jika itu tidak mungkin juga, kita tidak hanya perlu mengonversi PKCS#12 ke PEM, tetapi juga harus membuat file sementara yang berisi data PEM (tidak terenkripsi).

Perhatikan bahwa poin terakhir adalah apa yang pada dasarnya saya lakukan saat ini, tetapi saya tidak menyukai ini sama sekali. Mengapa saya tidak dapat memberikan string sederhana ke OpenSSL yang berisi sertifikat? Selain itu, mengapa saya tidak dapat meneruskan nama file dan kata sandi PKCS#12 ke lapisan bawah?

Saya akan menandai @reaperhulk sebagai pakar OpenSSL, tetapi pemahaman saya adalah bahwa tidak ada API untuk OpenSSL untuk memuat sertifikat format PKCS#12 untuk sertifikat klien. Ini berarti kita harus benar-benar mengonversi ke PEM. Melakukannya dalam memori tentu saja mungkin, tetapi pada titik tertentu saya bertanya-tanya apakah kami tidak hanya ingin mempertimbangkan ahli ini sehingga kami akan mendelegasikan ke SSLContext apa pun yang Anda berikan kepada kami.

@Lukasa Terima kasih telah menangani masalah ini dengan serius. Maaf jika ini terdengar terlalu teknis, tetapi pada dasarnya hanya ini:

Anda ingin mengakses layanan melalui sertifikat klien. Hampir di mana-mana Anda mendapatkan ini sebagai file dan kata sandi (di mana file tersebut dikodekan PKCS#12). Di sebagian besar API, seperti pustaka standar Java, Anda cukup memberinya nama file dan kata sandi, dan selesai.

Namun, dalam Python ini sangat rumit.

Itu sebabnya hampir tidak ada yang melakukannya. Sebagai gantinya, mereka mengonversi file dan kata sandi mereka ke file PEM dengan tangan, melalui OpenSSL, dan menggunakan file itu. Ini adalah biaya administrasi untuk setiap pengguna aplikasi semacam itu. Karena mereka tidak bisa begitu saja memberi nama file dan kata sandi (PKCS#12).

Saya pikir perpustakaan requests harus membuatnya setidaknya sesederhana di Jawa.

requests sudah melakukan pekerjaan yang baik dalam menyederhanakan API kompleks yang bodoh, dan kasus penggunaan PKCS#12 hanyalah contoh lain dari API kompleks yang bodoh.

kasus penggunaan PKCS#12 hanyalah contoh lain dari API kompleks yang bodoh.

Ya, saya sama sekali tidak setuju dengan itu: Saya akan sangat senang memiliki semacam solusi untuk dukungan PKCS#12 di suatu tempat di tumpukan.

Apa yang saya coba rasakan adalah kode apa yang diperlukan untuk membuatnya berfungsi, dan sebagai hasilnya di mana ini harus ditempatkan. Alasan saya seperti ini:

  1. Secara umum, Permintaan hanya ditambahkan ke permukaan API-nya jika ada utilitas substansial dalam melakukannya (yaitu, jika digunakan oleh banyak orang atau sangat banyak digunakan oleh beberapa orang), dan jika hal yang kami lakukan sulit untuk dilakukan dengan benar atau memiliki kasus tepi halus.
  2. Biasanya mendukung PKCS#12 akan dihitung sebagai tambahan ke permukaan API, tetapi jika itu tidak mengubah sintaks cert= sama sekali (hanya memperluas hal-hal yang akan didukungnya) dan tidak mengurangi perilaku ( yaitu, kami dapat dengan andal membedakan antara file PKCS#12 dan file PEM, atau kami dapat dengan mudah memproses melalui kedua rantai logika), saya akan mengatakan itu dianggap sebagai perubahan yang cukup kecil ke permukaan yang mungkin sepadan .
  3. Namun, ada tempat lain yang bisa dikunjungi. Misalnya pada level Transport Adapter, atau sebagai helper di Requests Toolbelt, atau yang lainnya.

Itu berarti saya ingin mempertimbangkan seberapa halus ini, seberapa rumit kodenya, apakah memerlukan dependensi ekstra, dan kemudian menggunakan informasi itu untuk mencari tahu di mana sebaiknya meletakkan kode. Sebagai contoh, saya memiliki _suspicion_ sekarang bahwa perpustakaan standar tidak dapat menangani PKCS#12, yang berarti bahwa _at best_ Permintaan hanya akan dapat menggunakan PKCS#12 dengan tambahan [security] terpasang. Dalam kasus yang lebih buruk lagi, kami mungkin tidak memiliki fungsi yang tersedia dalam pengikatan OpenSSL sama sekali, dalam hal ini kami harus melakukan beberapa hal gila untuk membuatnya berfungsi. Itu sebabnya saya ingin @reaperhulk mempertimbangkan: dia kemungkinan akan dapat mengklarifikasi ini untuk kami lebih cepat daripada yang bisa saya lakukan untuk penelitian.

Saya ingin melihat dukungan ini ditambahkan: Saya hanya perlu meminta beberapa orang yang tahu apa ruang lingkup pekerjaannya untuk berkomentar di sini dan memberi tahu saya seberapa besar gunung yang perlu kita pindahkan sebenarnya.

Satu detail lagi untuk implementasi PKCS#12: Versi lama dari binding OpenSSL Python gagal jika kata sandi diberikan sebagai objek unicode alih-alih string byte. Jadi itu harus dikonversi sebelum meneruskannya ke load_pkcs12() seperti ini:

if isinstance(password, unicode):
    password_bytes = password.encode('utf8')
else:
    password_bytes = password
pkcs12 = OpenSSL.crypto.load_pkcs12(pkcs12_data, password_bytes)

Konverter lengkap mungkin terlihat seperti ini, di mana pkcs12_data diharapkan menjadi string byte dengan data biner, sedangkan password mungkin berupa string byte atau string unicode:

def pkcs12_to_pem(pkcs12_data, password):
    # Old versions of OpenSSL.crypto.load_pkcs12() fail if the password is a unicode object
    if isinstance(password, unicode):
        password_bytes = password.encode('utf8')
    else:
        password_bytes = password
    p12 = OpenSSL.crypto.load_pkcs12(pkcs12_data, password_bytes)
    p12_cert = p12.get_certificate()
    p12_key = p12.get_privatekey()
    pem_cert = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, p12_cert)
    pem_key = OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, p12_key)
    pem = pem_cert + pem_key
    return pem

Diskusi PKCS#12 bagi saya tampaknya berada di luar cakupan masalah awal, karena masalah yang dimaksud adalah apakah permintaan harus mendukung PKCS#12 secara native. Saya akan memilih itu mendapat masalah sendiri, tapi jelas itu terserah orang-orang yang bertanggung jawab.

Yang mengatakan, sebagai solusi yang tidak memerlukan file temp tidak terenkripsi, metode OpenSSL.crypto.dump_privatekey memiliki parameter frasa sandi opsional, sehingga Anda bisa mendapatkan salinan kunci pribadi terenkripsi dalam format PEM dengan cara itu. Itu akan mengurangi ini menjadi masalah PEM terenkripsi yang kami mulai.

Atau, Anda mungkin juga dapat menulis peretasan yang mirip dengan yang saya sarankan sebelum menggunakan metode use_privatekey dari OpenSSL.SSL.Context . Dari atas kepalaku (belum diuji) sesuatu seperti

# From somewhere
pkcs12_data = ...
password_bytes = ...

class Pkcs12Context(requests.packages.urllib3.contrib.pyopenssl.OpenSSL.SSL.Context):
    def __init__(self, method):
        super(PasswordContext, self).__init__(method)
        p12 = OpenSSL.crypto.load_pkcs12(pkcs12_data, password_bytes)
        self.use_certificate(p12.get_certificate())
        self.use_privatekey(p12.get_privatekey())
# Monkey-patch the subclass into OpenSSL.SSL so it is used in place of the stock version
requests.packages.urllib3.contrib.pyopenssl.OpenSSL.SSL.Context = Pkcs12Context

Kemudian gunakan saja requests.get dll tanpa menentukan sertifikat sama sekali, karena sudah ditangani di konstruktor.

Meninjau utas ini sekarang. Pengulangan dari aslinya:

diberikan sertifikat klien berformat PEM terenkripsi, dapatkah permintaan menangani pemberian kata sandi?

Karena ini ada di lib standar saat ini, akan sangat bagus untuk mengintegrasikan opsi ini. Ini akan sangat berharga untuk pertimbangan keamanan perusahaan (di mana sertifikat kami dienkripsi, dan dimaksudkan untuk tetap demikian).

Pada titik ini, ini dapat dilakukan dengan meneruskan konteks ssl khusus ke urllib3 menggunakan adaptor transport. Ini dapat melakukan apa pun yang diizinkan oleh konteks ssl perpustakaan standar. Anda dapat melihat contoh melewati konteks khusus di sini .

Saya dapat menggunakan .pfx dan .p12 dengan permintaan dengan mengubahnya menjadi .pem menggunakan file sementara. Lihat https://Gist.github.com/erikbern/756b1d8df2d1487497d29b90e81f8068

Jika ada minat, saya bisa mengajukan PR. Akan sangat bagus untuk menghindari file sementara dan manajer konteks. Biarkan aku tahu.

Ini sepertinya tidak akan digabungkan, saya khawatir, tetapi perhatikan bahwa Anda sekarang dapat meneruskan konteks PyOpenSSL langsung ke Permintaan melalui adaptor transportasi, sehingga Anda mungkin menemukan bahwa Anda dapat menghindari masalah itu.

Ini sepertinya tidak akan digabungkan, saya khawatir, tetapi perhatikan bahwa Anda sekarang dapat meneruskan konteks PyOpenSSL langsung ke Permintaan melalui adaptor transportasi, sehingga Anda mungkin menemukan bahwa Anda dapat menghindari masalah itu.

maaf karena bingung tetapi apakah Anda mengatakan dukungan pfx/p12 secara umum kemungkinan tidak akan digabungkan? (dengan asumsi dilakukan dengan cara yang benar, melalui konteks dll). Senang mencobanya tetapi jelas tidak sepadan dengan waktu saya jika tidak akan digabungkan.

Saya percaya "tidak mungkin digabungkan" adalah tentang solusi file sementara.

@erikbern Untuk lebih jelasnya, saya senang mendekati dan menggabungkan solusi apa pun yang berfungsi agak konsisten. Misalnya, solusi untuk menggunakan PKCS#12 melalui modul kontribusi PyOpenSSL di urllib3 dapat diterima.

Namun, solusi file sementara tidak dapat diterima (seperti yang dicatat oleh @vog). Ini berarti dukungan untuk PKCS#12 tidak mungkin berfungsi dengan pustaka standar, karena modul pustaka standar ssl tidak mengekspos dukungan apa pun untuknya, sehingga tidak akan didukung di semua konfigurasi Permintaan.

Kedengarannya bagus. Saya juga setuju bahwa file temp buruk karena ada risiko keamanan menyimpan kunci yang didekripsi pada disk. Mungkin bisa dilihat minggu depan. Terima kasih atas perhatiannya tentang modul ssl – jika batasannya di luar requests maka jelas itu akan lebih rumit

Saya memeriksanya dan modul ssl menambahkan argumen cadata mana Anda dapat meneruskan data pem sebagai string mentah: https://docs.python.org/3/library/ssl.html #ssl.SSLContext.load_verify_locations

Kami harus menambal urllib3 di banyak tempat untuk membuat ini berfungsi, jadi saya mungkin mulai dari sana

@erikbern Untuk lebih jelasnya, hampir semua solusi seperti itu akan bekerja lebih baik hanya dengan meneruskan objek SSLContext dikonfigurasi dengan tepat ke urllib3 menggunakan TransportAdapter .

https://github.com/kennethreitz/requests/issues/2519 tampaknya identik dengan masalah ini, jadi mereka mungkin harus digabungkan

Pembaruan apa pun tentang masalah ini Saya mencoba menggunakan sertifikat Klien yang dienkripsi kata sandi dan tidak dapat membuatnya berfungsi. Haruskah saya mencari opsi lain selain permintaan? Bisa tolong di respon secepatnya.

Apakah kita mendokumentasikan ini? Saya merasa ini adalah fitur kami yang paling banyak diminta.

Saya percaya utas ini dimulai pada tahun 2013 dan saya tidak menemukan resolusi yang dijelaskan sampai akhir. Apakah kalian memberikan opsi untuk memberikan kata sandi? atau ini masih dalam proses?

Saya mencoba menggunakan permintaan dalam produk keamanan Aplikasi yang saya buat. Jadi setiap petunjuk akan sangat membantu

@AnoopPillai Apakah Anda memeriksa komentar ini? https://github.com/requests/requests/issues/1573#issuecomment -188125157

Ya, saya memang membaca komentar ini, ini adalah solusi tetapi Dalam kasus saya, saya tidak ingin mengubahnya menjadi 2 file sertifikat karena itu harus dilakukan di luar aplikasi saya. Terlebih lagi kami menggunakan lemari besi untuk menyimpan kata sandi untuk file .pem terenkripsi.

Kata sandi ini diambil secara dinamis oleh aplikasi pada saat dijalankan sehingga tidak ada hard coding.

@AnoopPillai Baiklah.

@kennethreitz Tidak, kami tidak mendokumentasikannya.

@AnoopPillai Ya, ini berfungsi dengan baik. Anda hanya perlu menggunakan beberapa kait tingkat rendah. Dalam hal ini, kami mengizinkan Anda untuk meneruskan SSLContext ke urllib3 secara langsung di tingkat Adaptor Transport. Ini memungkinkan Anda mengakses fungsi dasar yang memungkinkan Anda memberikan fungsi frasa sandi atau frasa sandi. Ini adalah bagaimana kami menyarankan Anda untuk mendukung ini.

@AnoopPillai solusi menggunakan file temp yang menurut saya berguna: https://Gist.github.com/erikbern/756b1d8df2d1487497d29b90e81f8068

Terima kasih Lukasa karena telah memberi tahu saya bahwa ada cara untuk melakukannya.
Saya sangat baru mengenal python dan saya menggunakan versi 3.6. Bisakah Anda memandu saya di mana saya dapat menemukan opsi seperti sandi untuk meneruskan kata sandi sertifikat klien.
@Erikbern Saya belum melalui solusi file temp namun akan melihat hal yang sama hari ini. Terima kasih atas tanggapannya.

@AnoopPillai Anda akan menginginkan load_cert_chain .

@Lukasa maukah Anda mendokumentasikannya? hanya perlu beberapa menit (saya sedang berpikir di bagian lanjutan, atau mungkin di bagian lanjutan lanjutan yang baru)

Maaf teman-teman, kurangnya pengalaman saya dengan python bisa menjadi alasannya tetapi saya tidak dapat memodifikasi kode yang dijelaskan Lukasa di atas. Kode saya adalah:

class DESAdapter(HTTPAdapter):
    """
    A TransportAdapter that re-enables 3DES support in Requests.
    """
    def init_poolmanager(self, *args, **kwargs):
        context = create_urllib3_context(load_cert_chain='rtmqa-clientid.pem',password='weblogic')
        kwargs['ssl_context'] = context
        return super(DESAdapter, self).init_poolmanager(*args, **kwargs)

    def proxy_manager_for(self, *args, **kwargs):
        context = create_urllib3_context(load_cert_chain='rtmqa-clientid.pem', password='weblogic')
        kwargs['ssl_context'] = context
        return super(DESAdapter, self).proxy_manager_for(*args, **kwargs)
s = requests.Session()
s.mount(url, DESAdapter())
r = s.get(url, headers=request_header).json()

dan saya mendapatkan kesalahan
TypeError: create_urllib3_context() mendapat argumen kata kunci yang tidak terduga 'load_cert_chain'

Itu kesalahan, ya. Anda ingin memanggil create_urllib3_context dan mendapatkan nilai kembaliannya, lalu memanggil load_cert_chain pada objek yang dikembalikan. Cobalah bermain-main dengan fungsi-fungsi tersebut di interpreter interaktif untuk melihat cara kerjanya.

Urllib3..util.ssl_.py yang diinstal pada mac saya tidak memiliki opsi terbaru untuk kata sandi.
ini kodenya

    if certfile:
        context.load_cert_chain(certfile, keyfile)
    if HAS_SNI:  # Platform-specific: OpenSSL with enabled SNI
        return context.wrap_socket(sock, server_hostname=server_hostname)

Opsi kata sandi tidak ada. Bagaimana cara memperbarui ssl_.py untuk mendapatkan versi terbaru?

@AnoopPillai Anda tidak. Panggil fungsi tanpa argumen, lalu panggil load_cert_chain pada objek yang dikembalikan. Anda tidak perlu mengubah urllib3.

Agar lebih jelas, seperti ini:

ctx = create_urllib3_context()
ctx.load_cert_chain(your_arguments_here)

Ayo dokumentasikan :)

@ erikbern Saya mencoba solusi tempfile Anda Tapi saya mendapatkan kesalahan berikut:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/urllib3/contrib/pyopenssl.py", line 441, in wrap_socket
    cnx.do_handshake()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/OpenSSL/SSL.py", line 1716, in do_handshake
    self._raise_ssl_error(self._ssl, result)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/OpenSSL/SSL.py", line 1456, in _raise_ssl_error
    _raise_current_error()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/OpenSSL/_util.py", line 54, in exception_from_error_queue
    raise exception_type(errors)
OpenSSL.SSL.Error: [('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')]

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/urllib3/connectionpool.py", line 595, in urlopen
    self._prepare_proxy(conn)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/urllib3/connectionpool.py", line 816, in _prepare_proxy
    conn.connect()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/urllib3/connection.py", line 326, in connect
    ssl_context=context)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/urllib3/util/ssl_.py", line 329, in ssl_wrap_socket
    return context.wrap_socket(sock, server_hostname=server_hostname)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/urllib3/contrib/pyopenssl.py", line 448, in wrap_socket
    raise ssl.SSLError('bad handshake: %r' % e)
ssl.SSLError: ("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')],)",)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/requests/adapters.py", line 440, in send
    timeout=timeout
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/urllib3/connectionpool.py", line 639, in urlopen
    _stacktrace=sys.exc_info()[2])
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/urllib3/util/retry.py", line 388, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='credit-cards-accounts-qa.kdc.capitalone.com', port=443): Max retries exceeded with url: /credit-cards-accounts/credit-cards/accounts/XqLuxBTABbIDvpw56ba34p2WV9JoWUSkPJ09hrBlWD8= (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')],)",),))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/tsu892/Desktop/Office/Pythone-work/ASR-pythone/ASR-python3.6/test-request.py", line 48, in <module>
    r = requests.get(url, headers=request_header, cert=cert).json()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/requests/api.py", line 72, in get
    return request('get', url, params=params, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/requests/api.py", line 58, in request
    return session.request(method=method, url=url, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/requests/sessions.py", line 508, in request
    resp = self.send(prep, **send_kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/requests/sessions.py", line 618, in send
    r = adapter.send(request, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/requests/adapters.py", line 506, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='credit-cards-accounts-qa.kdc.capitalone.com', port=443): Max retries exceeded with url: /credit-cards-accounts/credit-cards/accounts/XqLuxBTABbIDvpw56ba34p2WV9JoWUSkPJ09hrBlWD8= (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')],)",),))

Di bawah ini adalah kode saya:

import requests
import json
import OpenSSL.crypto
import tempfile
import os
import contextlib
import ssl

json_file='apiInput.json'
hdr_key=[]
hdr_value=[]
json_data=open(json_file)
data = json.load(json_data)
request_body={}
#pprint(data)
json_data.close()
request_data = data['request1']
request_header=request_data['header-data']
url=request_header['url']

@contextlib.contextmanager
def pfx_to_pem():
    print('inside pfx tp pem')
    with tempfile.NamedTemporaryFile(suffix='.pem') as t_pem:
        f_pem = open(t_pem.name, 'wb')
        fr_pfx = open('rtmqa-clientid.pfx', 'rb').read()
        p12 = OpenSSL.crypto.load_pkcs12(fr_pfx,'xxxxxxxxx')
        f_pem.write(OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, p12.get_privatekey()))
        f_pem.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, p12.get_certificate()))
        ca = p12.get_ca_certificates()
        if ca is not None:
            for cert in ca:
                f_pem.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert))
        f_pem.close()
        yield t_pem.name

with pfx_to_pem() as cert:
    print(cert)
    r = requests.get(url, headers=request_header, cert=cert).json()
print(r.status_code)
print(r.json())

maaf, sulit untuk mengetahui mengapa itu melanggar melihat dari komentar Anda. saya telah menggunakannya untuk banyak aplikasi dan tidak memiliki masalah apapun

@Lukasa Saya memang mencoba dengan perubahan kode itu (kode disisipkan di bawah) dan berakhir dengan kesalahan yang sama yang saya dapatkan dengan metode tempfile.

import requests
import json
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.ssl_ import create_urllib3_context

json_file='apiInput.json'
hdr_key=[]
hdr_value=[]
json_data=open(json_file)
data = json.load(json_data)
request_body={}
#pprint(data)
json_data.close()
request_data = data['request1']
request_header=request_data['header-data']
url=request_header['url']

class DESAdapter(HTTPAdapter):
    """
    A TransportAdapter that re-enables 3DES support in Requests.
    """
    def init_poolmanager(self, *args, **kwargs):
        context = create_urllib3_context()
        context.load_cert_chain('rtmqa-clientid.pem',password='weblogic')
        kwargs['ssl_context'] = context
        return super(DESAdapter, self).init_poolmanager(*args, **kwargs)

    def proxy_manager_for(self, *args, **kwargs):
        context = create_urllib3_context()
        context.load_cert_chain('rtmqa-clientid.pem',password='weblogic')
        kwargs['ssl_context'] = context
        return super(DESAdapter, self).proxy_manager_for(*args, **kwargs)

s = requests.Session()
s.headers=request_header
s.mount(url, DESAdapter())
r = s.get(url)
/Users/tsu892/Python3.6/bin/python /Users/tsu892/Desktop/Office/Pythone-work/ASR-pythone/ASR-python3.6/Test-ASRreq.py
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/urllib3/contrib/pyopenssl.py", line 441, in wrap_socket
    cnx.do_handshake()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/OpenSSL/SSL.py", line 1716, in do_handshake
    self._raise_ssl_error(self._ssl, result)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/OpenSSL/SSL.py", line 1456, in _raise_ssl_error
    _raise_current_error()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/OpenSSL/_util.py", line 54, in exception_from_error_queue
    raise exception_type(errors)
OpenSSL.SSL.Error: [('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')]

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/urllib3/connectionpool.py", line 595, in urlopen
    self._prepare_proxy(conn)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/urllib3/connectionpool.py", line 816, in _prepare_proxy
    conn.connect()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/urllib3/connection.py", line 326, in connect
    ssl_context=context)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/urllib3/util/ssl_.py", line 329, in ssl_wrap_socket
    return context.wrap_socket(sock, server_hostname=server_hostname)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/urllib3/contrib/pyopenssl.py", line 448, in wrap_socket
    raise ssl.SSLError('bad handshake: %r' % e)
ssl.SSLError: ("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')],)",)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/requests/adapters.py", line 440, in send
    timeout=timeout
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/urllib3/connectionpool.py", line 639, in urlopen
    _stacktrace=sys.exc_info()[2])
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/urllib3/util/retry.py", line 388, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='credit-cards-accounts-qa.kdc.capitalone.com', port=443): Max retries exceeded with url: /credit-cards-accounts/credit-cards/accounts/XqLuxBTABbIDvpw56ba34p2WV9JoWUSkPJ09hrBlWD8= (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')],)",),))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/tsu892/Desktop/Office/Pythone-work/ASR-pythone/ASR-python3.6/Test-ASRreq.py", line 37, in <module>
    r = s.get(url)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/requests/sessions.py", line 521, in get
    return self.request('GET', url, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/requests/sessions.py", line 508, in request
    resp = self.send(prep, **send_kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/requests/sessions.py", line 618, in send
    r = adapter.send(request, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/requests/adapters.py", line 506, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='credit-cards-accounts-qa.kdc.capitalone.com', port=443): Max retries exceeded with url: /credit-cards-accounts/credit-cards/accounts/XqLuxBTABbIDvpw56ba34p2WV9JoWUSkPJ09hrBlWD8= (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')],)",),))

@erikbern mungkinkah itu masalah pengaturan di laptop saya. Saya menggunakan mac, Pythone3.6

6c40089ea258:~ tsu892$ pip3 show requests
Name: requests
Version: 2.18.4
Summary: Python HTTP for Humans.
Home-page: http://python-requests.org
Author: Kenneth Reitz
Author-email: [email protected]
License: Apache 2.0
Location: /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages
Requires: idna, certifi, chardet, urllib3
6c40089ea258:~ tsu892$ pip3 show certifi
Name: certifi
Version: 2017.7.27.1
Summary: Python package for providing Mozilla's CA Bundle.
Home-page: http://certifi.io/
Author: Kenneth Reitz
Author-email: [email protected]
License: MPL-2.0
Location: /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages
Requires: 

Apakah menurut Anda ada yang salah dengan sertifikasi?

Apa output dari python -m requests.help ?

@Lukasa Outputnya adalah:

6c40089ea258:~ tsu892$ python3 -m requests.help?
/Library/Frameworks/Python.framework/Versions/3.6/bin/python3: No module named requests.help?

Harap hapus tanda tanya dari baris perintah Anda.

6c40089ea258:~ tsu892$ python3 -m requests.help
{
  "chardet": {
    "version": "3.0.4"
  },
  "cryptography": {
    "version": "2.0.3"
  },
  "idna": {
    "version": "2.6"
  },
  "implementation": {
    "name": "CPython",
    "version": "3.6.2"
  },
  "platform": {
    "release": "16.7.0",
    "system": "Darwin"
  },
  "pyOpenSSL": {
    "openssl_version": "1010006f",
    "version": "17.2.0"
  },
  "requests": {
    "version": "2.18.4"
  },
  "system_ssl": {
    "version": "100020bf"
  },
  "urllib3": {
    "version": "1.22"
  },
  "using_pyopenssl": true
}

Jadi kesalahan yang Anda dapatkan disebabkan oleh kami tidak dapat memvalidasi sertifikat TLS server. certifi dan OpenSSL sepertinya benar, jadi saya menganggap servernya salah tingkah. Server apa yang Anda coba jangkau?

Aplikasi ini disebarkan di Cloud AWS. Tetapi ketika kami memanggil API, pertama-tama pergi ke OSB yang mengotentikasi sertifikat dan kemudian merutekan permintaan ke AWS.
Saya menggunakan sertifikat yang sama dan menggunakan tukang pos atau kode Ruby saya, API berfungsi dengan baik

Apakah Anda memerlukan sertifikat root tertentu? Bisakah Anda memberikan nama host yang dihubungi untuk saya?

URL Host tanpa jalur adalah https://credit-cards-accounts-qa.kdc.capitalone.com
Ini adalah titik akhir internal

Ya, jadi saya tidak bisa melihat apa yang terjadi di sana. Bisakah Anda menjalankan openssl s_client -showcerts -connect credit-cards-accounts-qa.kdc.capitalone.com:443 dan memberikan output lengkap?

Dihapus

Ini terlihat seperti Anda tidak menggunakan sertifikat root tepercaya secara global. Di mana sertifikat root untuk layanan itu?

Saya tidak menggunakan sertifikat lain. Tidak yakin apakah di balik layar ada sertifikat root yang digunakan, apakah ada cara bagi saya untuk mengetahuinya?

Ya, Alat pengembang Chrome akan memberi tahu Anda rantai sertifikat lengkap yang digunakannya.

Anda mungkin tidak ingin memposting beberapa sertifikat internal online untuk dilihat siapa pun ...

@erikbern Ini adalah informasi publik. Anda dapat mencapai hasil yang sama dengan menjalankan perintah yang sama.

@SethMichaelLarson Dari profil GitHub @erikbern "Chief Troll Officer". Mungkin mereka hanya trolling?

@erikbern @sigmavirus24 Ah! Aku tidak tahu dengan siapa aku berbicara. Memproses! 🙇

Saya tidak dapat melihat apa pun kecuali sertifikat sha-1 ketika saya lari dari tukang pos
Mungkin saya perlu menambahkan ini entah bagaimana ke Pycharm

Jika Anda benar-benar menjelajah ke situs web di Chrome, itu sudah cukup.

@SethMichaelLarson menjalankan perintah apa? FYI komentar telah dihapus sekarang tetapi ada seluruh gumpalan BEGIN CERTIFICATE di sini sebelumnya ... afaik Anda tidak ingin membagikannya secara online

@erikbern Itu hanya kunci publik untuk sertifikat...

Sertifikat adalah data publik; mereka ditransmisikan dalam plaintext melalui jaringan pada setiap upaya koneksi.

Saya pergi ke rantai sertifikat dan hanya menemukan sertifikat Sha-1 dan sertifikat .Pem yang saya gunakan untuk menekan API

@AnoopPillai Saya mendapatkan kode contoh Anda dari 1 Sep berfungsi tanpa masalah menggunakan file pem sisi klien dengan kata sandi. Tampaknya tuan rumah menggunakan sertifikat biasa. Dengan @Lukasa terima kasih banyak!

Sayangnya saya masih mengalami masalah, bahkan dengan metode File Temp. Saya dapat menggunakan .pfx di Google Postman dan tidak memiliki masalah autentikasi (jadi saya tahu kredensial saya berfungsi), tetapi saya masih mendapatkan 401 dengan Python. Sayangnya orang dukungan dari perusahaan yang saya hadapi belum banyak membantu - apakah ada yang punya saran untuk pemecahan masalah?

Pada tahap ini saya benar-benar tidak yakin ke mana harus mencari masalah karena orang lain melaporkan keberhasilan dengan metode File Temp dan saya masih belum mendengar apa pun dari tim Manajemen Cert mereka.

Saran apa pun akan sangat dihargai - beri tahu saya jika saya dapat memberikan informasi tambahan untuk mempermudah ini.

Terima kasih :)

Sekedar saran, apakah Anda mencoba mengonversi PFX ke PEM? Juga, jika server juga menggunakan nama pengguna/kata sandi, Anda harus menambahkan permintaan get/post menggunakan auth=(). Saya telah menggunakan pendekatan class DESAdapter(HTTPAdapter) atas selama beberapa minggu sekarang tanpa masalah, menggunakan file PEM yang dilindungi kata sandi.

@ideasean Masih mendapatkan kredensial yang tidak valid. Saya harus mengarahkan load_cert_chain ke file .pem yang dihasilkan oleh fungsi pfx_to_pem yang ditulis untuk metode File Temp, benar? Ini memiliki kunci pribadi dan sertifikat di dalamnya.

Karena .pfx bekerja dengan Postman tetapi tidak akan mengautentikasi di sini, dapatkah itu berarti ada yang tidak beres dalam proses konversi?

Saya tidak menggunakan metode file temp. Saya menggunakan pendekatan DESAdapter cukup banyak seperti yang ditulis dalam posting AnoopPillai pada Sep1 di atas dimulai dengan -

Saya memang mencoba dengan perubahan kode itu (kode disisipkan di bawah) dan berakhir dengan kesalahan yang sama yang saya dapatkan dengan metode tempfile.

Saya tidak dapat berbicara dengan proses konversi, tetapi mungkin tes yang baik adalah mencoba menggunakan file pem yang dikonversi dengan Postman?

Perhatikan juga bahwa saya menggunakan pendekatan di atas karena file pem saya dienkripsi/dilindungi kata sandi, dan permintaan Python saat ini tidak mendukungnya. Jika pem Anda akhirnya tidak dilindungi kata sandi, maka Anda harus dapat menggunakan permintaan asli per tautan (tetapi kemudian Anda akan memiliki sertifikat yang tidak dilindungi pada sistem file Anda).

@ideasean Saya memecah metode ini dan mendapatkan file .pem dengan Atribut dan Sertifikat Bag serta file .pem dengan Atribut Bag dan Kunci Pribadi Terenkripsi.

Masih mendapatkan kredensial yang tidak valid, saya kira saya akan mencoba memasukkan sertifikat ke Postman dan melihat apakah mereka berfungsi tetapi saya tidak tahu mengapa saya tampaknya tidak dapat membongkar .pfx ini dengan benar

Saya juga mencoba perintah openssl openssl pkcs12 -in <my_pfx>.pfx -out certificate.cer -nodes , dan itu masih memberi saya kesalahan 401 ketika saya mengubahnya seperti ini: context.load_cert_chain('certificate.cer')

Saya menginstal .cer yang disebutkan di atas dan Postman bahkan tidak meminta untuk menggunakannya ketika saya membuat panggilan API (tidak seperti popup ketika meminta untuk menggunakan .pfx), tidak yakin bagaimana lagi saya bisa membuatnya menggunakan sertifikat khusus itu karena tidak ada panel "Sertifikat" di pengaturan seperti yang dikatakan dokumen ada.

Anda mungkin menggunakan Postman versi browser, yang tidak menyertakan panel sertifikat, menonaktifkan validasi ssl, dll. Coba klien lengkap untuk mengubah pengaturan sertifikat. Anda mungkin ingin melanjutkan diskusi ini di utas yang berbeda, karena kami sedikit keluar dari topik.

@mkane848 melihat komentar asli Anda di mana Anda mendapatkan ValueError: String expected . Anda mungkin ingin memeriksa https://github.com/pyca/pyopenssl/issues/701 dan https://github.com/shazow/urllib3/issues/1275.

Saya menggunakan pem pribadi saya dengan kata sandi menggunakan ini:

from requests.adapters import HTTPAdapter

from urllib3.util.ssl_ import create_urllib3_context

class SSLAdapter(HTTPAdapter):
    def __init__(self, certfile, keyfile, password=None, *args, **kwargs):
        self._certfile = certfile
        self._keyfile = keyfile
        self._password = password
        return super(self.__class__, self).__init__(*args, **kwargs)

    def init_poolmanager(self, *args, **kwargs):
        self._add_ssl_context(kwargs)
        return super(self.__class__, self).init_poolmanager(*args, **kwargs)

    def proxy_manager_for(self, *args, **kwargs):
        self._add_ssl_context(kwargs)
        return super(self.__class__, self).proxy_manager_for(*args, **kwargs)

    def _add_ssl_context(self, kwargs):
        context = create_urllib3_context()
        context.load_cert_chain(certfile=self._certfile,
                                keyfile=self._keyfile,
                                password=str(self._password))
        kwargs['ssl_context'] = context

Sekadar informasi, saya baru saja menerapkan dukungan PKCS#12 untuk requests sebagai pustaka terpisah:

Kode ini adalah implementasi yang bersih : tidak menggunakan patch monyet atau file sementara. Sebagai gantinya, TransportAdapter khusus digunakan, yang menyediakan SSLContext khusus.

Setiap umpan balik dan peningkatan dipersilakan!

Tentu saja, saya berharap requests akan menyediakan fungsionalitas ini secara langsung, tetapi sampai kita berada di sana, perpustakaan ini akan mengurangi rasa sakitnya.

Akan sangat bagus jika kita bisa melakukan ini:

~~~
cert=("cert.pem", "key.pem", "somepassphrase") # sertifikat/kunci terpisah

cert=("keycert.pem", None, "somepassphrase")    # combined cert/key

~~~

...bahkan jika itu hanya bekerja pada python 3.3+. Ini hanya akan menjadi tambahan kecil pada permukaan API.

AFAICS, ini berarti perubahan kecil pada urllib3 sehingga HTTPSConnection menerima argumen password opsional; ini diturunkan melalui ssl_wrap_socket , berakhir dengan:

~jika file sertifikat:jika kata sandi bukan Tidak Ada:context.load_cert_chain(certfile, keyfile, kata sandi)lain:context.load_cert_chain(certfile, keyfile)~

Maka itu akan kompatibel ke belakang, memunculkan pengecualian hanya jika Anda mencoba menggunakan frasa sandi kunci pribadi pada platform lama yang tidak mendukungnya.

Perhatikan bahwa adaptor contrib/pyopenssl.py sudah mendukung argumen tambahan ini ke load_cert_chain , dan begitu juga python 2.7 .


Selain: Saya menggunakan AWS KMS untuk mengelola data "rahasia", jadi saya akan memuat kata sandi kunci saat runtime dari KMS, bukan mengkodekannya ke dalam aplikasi.

Saya pribadi tidak akan menentang perubahan ini, karena saya pikir itu akan sangat meningkatkan antarmuka pengguna kami untuk banyak pengguna di seluruh papan.

@sigmavirus24 ada pemikiran?

@candlerb @kennethreitz Apakah dapat diterima untuk memasukkan kasus PKCS#12 ke dalam API itu juga?

cert=('keycert.p12', None, 'somepassphrase')

Perbedaannya dapat berupa ekstensi file ( *.p12 versus *.pem ), atau dengan melihat byte pertama file itu.

Saya tidak punya masalah dengan mengizinkan permintaan untuk mengambil pkcs#12, selama itu dapat dilakukan dengan aman - dan menurut saya itu menghalangi penulisan kunci pribadi yang diekstraksi ke file sementara.

Googling untuk Python pkcs#12, saya menemukan:

  • Kode seseorang yang menuliskan kunci pribadi
  • Beberapa kode lain yang menurut saya bergantung pada pyOpenSSL untuk dibaca di pkcs#12. Ini mengembalikan sertifikat dan kunci sebagai item data.

Jadi melakukan ini, saya pikir perlu untuk menghubungkan semuanya sedemikian rupa sehingga kunci/sertifikat itu sendiri diteruskan ke OpenSSL, bukan nama file yang berisi hal-hal itu. Kedengarannya seperti perubahan yang jauh lebih besar.

Jika itu terlalu sulit, maka itu berarti bahwa pengguna harus mengonversi pkcs#12 ke PEM secara offline, yang cukup mudah (dan dapat didokumentasikan).

@candlerb Seperti yang saya tulis di komentar saya sebelumnya (https://github.com/requests/requests/issues/1573#issuecomment-348968658), saya sudah membuat implementasi bersih yang terintegrasi dengan baik dengan requests .

Jadi masalah yang Anda gambarkan sudah terpecahkan.

Saat ini implementasi saya menambahkan argumen kata kunci pkcs12_* , untuk menghindari sebanyak mungkin.

Tapi saya pikir itu harus diintegrasikan ke dalam argumen kata kunci cert , dan pertanyaan saya adalah:

  • Apakah itu dapat diterima secara umum?
  • Apakah proposal konkret saya cert=('keycert.p12', None, 'somepassphrase') dapat diterima?
  • Bagaimana seharusnya kita membedakan antara PKCS#12 dan PEM? (Dengan akhiran nama file, atau berdasarkan konten file?)

(Selain itu, saya lebih suka melihatnya di requests daripada perpustakaan requests_pkcs12 saya yang terpisah. Tetapi mengingat usia masalah ini, saya memiliki sedikit harapan bahwa ini akan naik ke hulu dalam waktu dekat. Namun , jika ada pernyataan konkret tentang jenis implementasi apa yang sebenarnya diinginkan, mungkin saya dapat menyesuaikan implementasi saya dan mengajukan permintaan tarik.)

Jadi, beberapa hal:

  1. Saya tidak berpikir kita harus mengambil kata kunci cert dan mengembangkannya seperti ini. Ini adalah data yang terstruktur secara implisit dan orang-orang sudah bingung dengan tupel dalam kata kunci files . Saya pikir melanjutkan pola yang diketahui buruk itu bodoh.

  2. Saya pikir jika ada, adaptor pkcs12 harus dimodifikasi dan di-upstream ke request-toolbelt. Saya pikir akan lebih baik untuk memodifikasinya untuk membuat ssl_context sekali daripada menyimpan kata sandi pkcs12 di memori pada objek itu.

Saya pikir masih ada pekerjaan lain yang perlu dilakukan sebelum kami dapat menangani ini dalam kasus yang lebih umum, apa pun yang terjadi dan itu termasuk menentukan API yang tepat untuk ini untuk Requests 3.0.

@ sigmavirus24 Terima kasih atas umpan baliknya.

  1. Oke, jadi mari kita simpan kata kunci pkcs12_* .
  2. Ya, itu pasti layak untuk ditingkatkan. Saya membuat entri pelacak masalah untuk itu: https://github.com/m-click/requests_pkcs12/issues/2

Bagaimana kelas PKCS#12 TransportAdapter dimasukkan ke dalam requests ? Apakah kelas itu hanya ditambahkan ke requests , atau apakah ada cara lain untuk memasukkannya pada level "lebih dalam", sehingga dapat digunakan tanpa pembungkus request()/get()/... dan tanpa harus memuatnya secara eksplisit adaptor?

Organisasi saya perlu menggunakan sertifikat PKCS12 dan bersedia melakukan peningkatan yang diperlukan pada perpustakaan Anda untuk melakukannya. Mendekripsi file .p12 ke file .pem dianggap terlalu berisiko dan menambahkan langkah ekstra untuk ditangani. Kami ingin menambahkan fungsionalitas untuk menghasilkan dan menyediakan ssl_context untuk sesi tertentu. Apakah fungsi ini masih dapat diterima oleh tim Anda dengan asumsi itu diterapkan dengan benar?

Hanya pengingat singkat: Implementasi bersih telah disediakan oleh perusahaan kami, tetapi sebagai adaptor terpisah: https://github.com/m-click/requests_pkcs12

Jangan ragu untuk memformatnya kembali menjadi permintaan tarik untuk permintaan itu sendiri.

Sepanjang jalan, Anda mungkin ingin memperbaiki masalah kecil: ssl_context tidak boleh disimpan di memori untuk seluruh sesi, tetapi sesegera mungkin, hanya untuk satu koneksi yang diberikan. Lihat juga:

Jika Anda memperbaikinya di sepanjang jalan, alangkah baiknya jika Anda dapat memberikannya sebagai permintaan tarik kecil ke https://github.com/m-click/requests_pkcs12 selain permintaan itu sendiri.

Dengan begitu, semua orang yang menggunakan perpustakaan requests_pkcs12 saat ini juga secara otomatis akan mendapat manfaat dari peningkatan itu, tanpa harus beralih ke API baru (yang kemudian ditingkatkan) untuk permintaan itu sendiri.

Ya, https://github.com/m-click/requests_pkcs12 bekerja untuk saya dan melakukan persis apa yang saya inginkan. Terima kasih banyak @vog ! Saya berharap permintaan dapat mendukung itu pada akhirnya.

Saya juga akan berterima kasih kepada @vog atas implementasinya, berfungsi seperti yang diharapkan, dan memecahkan masalah menyimpan sertifikat/kunci di penyimpanan yang tidak aman seperti S3 dalam kasus saya. Mudah-mudahan, ini bisa mencapai requests .

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

justlurking picture justlurking  ·  3Komentar

tiran picture tiran  ·  3Komentar

avinassh picture avinassh  ·  4Komentar

ReimarBauer picture ReimarBauer  ·  4Komentar

remram44 picture remram44  ·  4Komentar