Requests: حدد كلمة مرور لشهادة عميل SSL

تم إنشاؤها على ٣ سبتمبر ٢٠١٣  ·  121تعليقات  ·  مصدر: psf/requests

بقدر ما أعرف حاليًا ، لا يمكن تحديد كلمة المرور لشهادة جانب العميل التي تستخدمها للمصادقة.
هذه مشكلة صغيرة لأنك تريد دائمًا حماية كلمة المرور لملف pem. الذي يحتوي على المفتاح الخاص. لن يسمح لك openssl بإنشاء حساب بدون كلمة مرور.

Documentation Planned

التعليق الأكثر فائدة

botondus أعتقد أنني وجدت طريقة أبسط لتحقيق ذلك من خلال مكتبة الطلبات. أقوم بتوثيق هذا للأشخاص الآخرين الذين يواجهون المشكلة.

أفترض أن لديك شهادة .p12 وعبارة مرور للمفتاح.

إنشاء الشهادة والمفتاح الخاص.

// 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

حسنًا ، لم ننتهي بعد ونحتاج إلى إنشاء المفتاح الذي لا يتطلب كلمة مرور PEM في كل مرة يحتاج فيها إلى التحدث إلى الخادم.

توليد مفتاح بدون عبارة المرور.

// 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

الآن ، سيكون لديك certificate.pem و plainkey.pem ، وكلا الملفين مطلوب للتحدث إلى API باستخدام الطلبات.

فيما يلي مثال لطلب باستخدام هذه الشهادة والمفاتيح.

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()

أتمنى أن يساعدك هذا:

سم مكعبkennethreitzLukasa @ sigmavirus24

ال 121 كومينتر

شيء مثل:

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

متأكد تمامًا من أنه من المفترض أن تستخدم المعلمة cert لهذا: cert=('server.pem', 'my_password')

@ sigmavirus24
قيمة tuple هي (certificate, key) . لا يوجد حاليًا دعم لملفات المفاتيح المشفرة.
حصل stdlib فقط على دعم لتلك الموجودة في الإصدار 3.3.

Heh ، @ t-8ch ، لقد قمت بالربط بطريق الخطأ بملف على FS المحلي. ؛) الارتباط الصحيح .

صحيح تمامًا @ t-8ch. هذا هو السبب في أنني لا يجب أن أجيب على المشكلات من الحافلة مطلقًا. : /

لذا فإن الإجماع الحالي هو أننا لا نؤيد ذلك. ما مقدار العمل المحتمل لإضافة دعم في إصدارات غير 3.3 من Python؟

ما مدى صعوبة إلقاء خطأ في هذا الشرط؟ لقد واجهت للتو هذه المشكلة السخيفة واستغرق الأمر ساعتين لمعرفة ذلك ، سيكون من الجيد أن يحدث خطأ ، فهو حاليًا يجلس هناك بشكل متكرر. شكرا على المكتبة الرائعة!

انتظر ، يجلس حيث حلقات؟ أين نفشل في التنفيذ؟ يمكنك طباعة traceback من حيث نحن حلقة؟

يبدو أنه معلق هنا:

r = request.get (url،
المصادقة = headeroauth ،
سيرت = self.cert_tuple ،
رؤوس = رؤوس ،
المهلة = 10 ،
تحقق = صحيح)

حاولت تحويل المهلة لأعلى أو لأسفل دون جدوى ، لكنني أتخيل أنها تعرف جيدًا قبل انتهاء المهلة ، لا يمكنها استخدام الشهادة. شكرا!

آه ، آسف ، لم أكن واضحًا. قصدت تركه يتعطل ثم قتله باستخدام Ctrl + C بحيث يطرح Python استثناء KeyboardInterrupt ، ثم لنرى أين نحن في traceback. أريد أن أعرف في أي طلبات توقف التنفيذ.

ما يحدث (أو على الأقل ما رأيته في كثير من الحالات) هو أن OpenSSL ، عند منحه شهادة محمية بكلمة مرور ، سيطلب من المستخدم إدخال كلمة مرور. لا تظهر في أي سجلات (لأن المطالبة تمت طباعتها مباشرة) ، ولا تنتهي مهلة لأنها تنتظر أن يضغط المستخدم على إدخال.

وغني عن القول ، إنه سلوك مروع وخطير عند تشغيل الكود على الخادم (لأنه سيؤدي إلى تعليق العامل لديك دون أي خيار للاسترداد بخلاف قتل العملية).

هل هناك طريقة لجعل الطلبات تثير استثناءً في هذه الحالة بدلاً من المطالبة بكلمة مرور ، أم أن ذلك خارج عن سيطرتك تمامًا وفي يد OpenSSL؟

maxnoel ، أنا متأكد من أن هذا في يد OpenSSL ولكن إذا كان بإمكانك الإجابة على سؤال Lukasa (التعليق الأخير على هذه المشكلة) فسيكون من المفيد جدًا إعطاء إجابة محددة بشأن ما إذا كان هناك أي شيء يمكننا القيام به للمساعدة .

يمكنك التأكد من أن OpenSSL يحظر على stdin لعبارة المرور من موجه python التفاعلي:

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

إذا كنت تعمل من عملية في الخلفية ، أفترض أن OpenSSL سيحظر انتظار هذا الإدخال.

هذا صحيح. هل هناك أي طلبات يمكن أن تفعلها لمنع حدوث ذلك؟ سيكون رفع استثناء عندما لا يتم إعطاء كلمة مرور أكثر فائدة من المطالبة بالأشياء على stdin (خاصة في برنامج غير تفاعلي).

أخشى أنني لا أعرف بأي طريقة. تضمين التغريدة

هناك طرق لمنع OpenSSL من القيام بذلك ، لكنني لست متأكدًا مما إذا كانت قد تم الكشف عنها بواسطة pyOpenSSL. أين تقوم الطلبات باستدعاء pyopenssl لتحميل شهادة العميل؟ أستطيع أن أحفر قليلا.

reaperhulk يتم ذلك من في urllib3 ، هنا .

نقوم أيضًا بعمل شيء مشابه جدًا لـ stdlib ، والذي سيكون مشكلة منفصلة تمامًا.

لذلك يمكننا القيام بذلك باستخدام PyOpenSSL باستخدام تصحيح مثل هذا . في إصدار stdlib ، نحتاج إلى استخدام load_cert_chain بكلمة مرور.

هل تم حل هذه المشكلة؟ أقوم حاليًا بتشغيل هذا أثناء محاولة الاتصال بخادم Apache.

ما كانت.

ماذا عن حاويات PKCS # 12 المنسقة (والمشفرة) والتي يمكن أن تحتوي على شهادة / مفتاح عميل؟ هل يندرج هذا تحت نفس طلب الميزة؟

تضمين التغريدة

تضمين التغريدة
لدي نفس المشكلة ولقد بحثت كثيرًا في Google ، أخيرًا ، قمت بحلها باستخدام pycurl.
في موقفي ، أستخدم openssl لتحويل ملف .pfx إلى ملف .pem الذي يحتوي على كل من cert & key (المشفر بعبارة مرور) ، ثم استدعاء الكود التالي.

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()

راجع للشغل ، للأمان ، من الأفضل عدم عمل كود ثابت مقابل pass phrase

بالطبع. ومع ذلك ، فإن المشكلة ليست حقًا أن عبارة المرور مطلوبة - إنها أن OpenSSL يجعل برنامجك معلقًا أثناء انتظار شخص ما لكتابة عبارة مرور في stdin ، حتى في حالة وجود برنامج غير تفاعلي أو واجهة المستخدم الرسومية أو عن بُعد.

عندما تكون عبارة المرور مطلوبة ولا يتم توفير أي منها ، يجب رفع استثناء بدلاً من ذلك.

إذا كنت تستخدم عبارة مرور افتراضية للمفتاح "" ، فلن يتعطل opensl.
سيعيد نص كلمة مرور غير صالحة. يمكنك تغيير تدفق الطاقة الحرارية على الفور
لإعلام المستخدم بعد ذلك بدون توقف التطبيق هذا

أي خطة لإضافة هذه الميزة

نريد إضافته ، لكن ليس لدينا جدول زمني لإضافته في الوقت الحالي.

botondus أعتقد أنني وجدت طريقة أبسط لتحقيق ذلك من خلال مكتبة الطلبات. أقوم بتوثيق هذا للأشخاص الآخرين الذين يواجهون المشكلة.

أفترض أن لديك شهادة .p12 وعبارة مرور للمفتاح.

إنشاء الشهادة والمفتاح الخاص.

// 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

حسنًا ، لم ننتهي بعد ونحتاج إلى إنشاء المفتاح الذي لا يتطلب كلمة مرور PEM في كل مرة يحتاج فيها إلى التحدث إلى الخادم.

توليد مفتاح بدون عبارة المرور.

// 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

الآن ، سيكون لديك certificate.pem و plainkey.pem ، وكلا الملفين مطلوب للتحدث إلى API باستخدام الطلبات.

فيما يلي مثال لطلب باستخدام هذه الشهادة والمفاتيح.

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()

أتمنى أن يساعدك هذا:

سم مكعبkennethreitzLukasa @ sigmavirus24

لقد سمعت من خلال شجرة العنب أن أمازون تفعل هذا بالضبط داخليًا.

أنا أواجه هذه المشكلة أيضًا. ما يقلقني هو أنني لا أرغب في تخزين المفتاح الخاص البسيط في نظام الملفات (قد أتعرض لخطر السرقة من قبل الآخرين). لذا في رأيي ، الطريقة الأكثر قابلية للتوسيع لتنفيذ ذلك هي دعم استخدام شيء مثل PEM encoded string of private key بدلاً من مسار الملف لتحديد المفتاح الخاص. فقط ترك تشفير / فك تشفير المفتاح / الشهادة الخاصة للمطورين في طريقتهم المفضلة.
بعد قراءة الكود المصدري للطلبات ، يبدو أنه ليس من السهل تنفيذه نظرًا لأن الطلبات تعتمد على ssl lib الخاص بـ python الذي يدعم ملف الشهادة / المفتاح الخاص فقط. أنا فقط أتساءل عما إذا كان بإمكاننا استخدام pyopenssl بدلاً من python stdlib؟ يحتوي pyopenssl على غلاف اتصال openssl ، راجع: https://pyopenssl.readthedocs.io/en/latest/api/ssl.html#connection -objects. وبالتالي يمكننا استخدام كائن "pkey" كمفتاح خاص بدلاً من مسار الملف.

تدعم الطلبات بالفعل PyOpenSSL ، طالما تم تثبيتها وبعض التبعيات الأخرى المطلوبة. ومع ذلك ، لن يصبح هذا إلزاميًا أبدًا: من المهم بالنسبة لنا أن نعمل بشكل جيد مع المكتبة القياسية.

في إصدار مستقبلي ، سيكون لدينا دعم لتمرير كائنات SSLContext إلى urllib3 من أجل التعامل مع TLS: وهذا سيمكن هذه الوظيفة.

بالنسبة لأولئك الذين يواجهون هذه المشكلة ، حتى تضيف الطلبات القدرة على تمرير ssl.SSLContext / OpenSSL.SSL.Context إلى urllib3 ، إليك حل بديل يدعم بالفعل استخدام شهادة / ملف مفتاح مشفر (يتطلب تثبيت PyOpenSSL واستخدامه بدلاً من المكتبة القياسية ssl ، والذي يجب أن يكون إذا تم تثبيته)

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 : هل يعمل هذا أيضًا مع ملفات PKCS # 12 ، أم أن هذا PEM فقط؟

Lukasa : هل من المفترض حقًا معالجة قضية PKCS # 12 هنا ، أم يجب فتح إصدار منفصل لذلك؟

يعد PKCS # 12 مشكلة أكثر تعقيدًا ، ولكن ستحتاج في الأساس إلى القيام بكل ما هو مطلوب لتخصيص SSLContext الخاص بك.

Lukasa : كنت أفكر أكثر في توفير واجهة برمجة تطبيقات جيدة عالية المستوى في الطلبات. على سبيل المثال ، قم ببساطة بتقديم اسم الملف client_cert.p12 وكلمة المرور من خلال معلمة الكلمة الرئيسية cert=... .

vog ما هو الرمز الذي تعتقد أنه سيكون مطلوبًا لإنجاح هذا العمل؟

Lukasa لست متأكدًا من العناصر الداخلية لـ requests ، لذا ربما أقلل من قيمة ما هو موجود بالفعل ، لكنني أعتقد أن أحد الأشياء التالية يجب القيام به:

  • إما أن يكون لدينا طريقة لتوفير اسم ملف PKCS # 12 مباشرة إلى الطبقات السفلية (urllib3 ، إلخ). وربما كلمة المرور أيضًا. (لأنني لا أعرف أي شخص يريد مكتبة عناوين URL أن تطلب من المسؤول بشكل تفاعلي إدخال كلمة مرور PKCS # 12 على أداة تعمل من جانب الخادم.)
  • إذا كان ذلك مستحيلًا ، فسنحتاج إلى تحويل PKCS # 12 (+ كلمة المرور) إلى PEM ، ثم توفيرها للمستويات الأدنى. يتم ذلك من خلال بضع مكالمات مباشرة إلى الربط OpenSSL . ومع ذلك ، فإن النتيجة هي شهادة PEM كسلسلة ، ولم أجد بعد طريقة لتوفير PEM (غير المشفر) كسلسلة للطبقات السفلية (باستثناء ربما باستخدام غلاف OpenSSL / python "ssl" "buffer" ، على سبيل المثال wrap_bio ، لكن هذا متاح فقط في أحدث إصدارات Python 3 ، وليس Python 2).
  • لذلك إذا كان ذلك مستحيلًا ، فلن نحتاج فقط إلى تحويل PKCS # 12 إلى PEM ، ولكن يتعين علينا أيضًا إنشاء ملف مؤقت يحتوي على بيانات PEM (غير المشفرة).

لاحظ أن النقطة الأخيرة هي ما أفعله بشكل أساسي في الوقت الحالي ، لكنني لا أحب هذا على الإطلاق. لماذا لا يمكنني تقديم سلسلة بسيطة لـ OpenSSL تحتوي على الشهادة؟ علاوة على ذلك ، لماذا لا يمكنني ببساطة تمرير اسم الملف وكلمة المرور PKCS # 12 إلى الطبقات السفلية؟

سأقوم بوضع علامة في reaperhulk كخبير في OpenSSL ، لكن ما أفهمه هو أنه لا توجد واجهات برمجة تطبيقات لـ OpenSSL لتحميل شهادات تنسيق PKCS # 12 لشهادات العميل. هذا يعني أننا سنحتاج إلى التحويل تمامًا إلى PEM. من المؤكد أن القيام بذلك في الذاكرة أمر ممكن ، ولكن في مرحلة معينة أتساءل عما إذا كنا لا نريد فقط أن نعتبر هذا الخبير بما فيه الكفاية بحيث نقوم بتفويض أي SSLContext تمر به إلينا.

Lukasa نشكرك على التعامل مع هذه المشكلة بجدية. آسف إذا كان هذا يبدو تقنيًا للغاية ، ولكنه في الأساس هو هذا فقط:

تريد الوصول إلى خدمة من خلال شهادة العميل. في كل مكان تقريبًا تحصل عليه كملف وكلمة مرور (حيث يتم ترميز الملف PKCS # 12). في معظم واجهات برمجة التطبيقات ، مثل مكتبة Java القياسية ، يمكنك ببساطة إعطائها اسم الملف وكلمة المرور ، وتنتهي من ذلك.

ومع ذلك ، في بايثون هذا معقد مثل الجحيم.

لهذا السبب لا أحد يفعل ذلك تقريبًا. بدلاً من ذلك ، يقومون بتحويل ملفهم وكلمة المرور الخاصة بهم إلى ملف PEM يدويًا ، من خلال OpenSSL ، واستخدام هذا الملف. هذا هو الحمل الإداري لكل مستخدم لمثل هذا التطبيق. لأنهم لا يستطيعون ببساطة تسمية الملف وكلمة المرور (PKCS # 12).

أعتقد أن مكتبة requests يجب أن تجعلها على الأقل بسيطة مثل Java.

requests بالفعل بعمل رائع في تبسيط واجهات برمجة التطبيقات المعقدة الغبية ، وحالة استخدام PKCS # 12 هي مجرد مثال آخر لواجهة برمجة تطبيقات معقدة غبية.

حالة استخدام PKCS # 12 هي مجرد مثال آخر لواجهة برمجة تطبيقات معقدة غبية.

نعم ، أنا لا أختلف مع ذلك على الإطلاق: سأكون سعيدًا تمامًا لوجود نوع من الحل لدعم PKCS # 12 في مكان ما في المكدس.

ما أحاول الشعور به هو الرمز المطلوب لإنجاح هذا العمل ، ونتيجة لذلك يجب وضع هذا الرمز. تفكيري هو مثل هذا:

  1. بشكل عام ، تضيف الطلبات إلى سطح واجهة برمجة التطبيقات الخاصة بها فقط إذا كانت هناك فائدة كبيرة في القيام بذلك (أي ، إذا تم استخدامها من قبل الكثير من الأشخاص أو استخدامها بكثافة من قبل البعض) ، وإذا كان الشيء الذي نقوم به صعبًا أو لديها حالات حافة خفية.
  2. عادةً ما يتم احتساب دعم PKCS # 12 كإضافة إلى سطح API ، ولكن إذا لم يغير بناء الجملة cert= على الإطلاق (فقط يوسع الأشياء التي سيدعمها) ولا يتراجع عن السلوك ( وهذا يعني أنه يمكننا معرفة الفرق بين ملفات PKCS # 12 وملفات PEM بشكل موثوق ، أو يمكننا بسهولة المعالجة من خلال كلا سلسلتي المنطق) ، أود أن أقول أنه يعد تغييرًا طفيفًا بدرجة كافية على السطح الذي ربما يستحق ذلك .
  3. ومع ذلك ، هناك أماكن أخرى قد يذهب هذا. على سبيل المثال ، على مستوى محول النقل ، أو كمساعد في حزام أدوات الطلبات ، أو أي شيء آخر.

هذا يعني أنني أريد أن أفهم مدى دقة هذا ، ومدى تعقيد الكود ، وما إذا كان يتطلب تبعيات إضافية ، ثم استخدام هذه المعلومات لتحديد أفضل مكان لوضع الكود. على سبيل المثال ، لديّ شكوك في الوقت الحالي بأن المكتبة القياسية لا يمكنها معالجة PKCS # 12 ، مما يعني أن _ في أفضل الأحوال_ الطلبات ستكون قادرة فقط على استخدام PKCS # 12 مع تثبيت [security] إضافي. في حالة أسوأ ، قد لا تكون لدينا الوظائف المتاحة في أي رابط OpenSSL على الإطلاق ، وفي هذه الحالة سيتعين علينا القيام ببعض الأشياء المجنونة الحقيقية لجعلها تعمل. لهذا السبب أردت من reaperhulk أن

أود أن أرى هذا الدعم مضافًا: أحتاج فقط إلى الحصول على بعض الأشخاص الذين يعرفون نطاق العمل للتعليق هنا وإخباري بمدى ضخامة الجبل الذي نحتاج إلى نقله بالفعل.

أحد التفاصيل الإضافية لتطبيق PKCS # 12: تفشل الإصدارات القديمة من روابط Python OpenSSL إذا تم إعطاء كلمة المرور ككائن unicode بدلاً من سلسلة بايت. لذلك يجب تحويلها قبل تمريرها إلى load_pkcs12() مثل هذا:

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

قد يبدو المحول الكامل على هذا النحو ، حيث يُتوقع أن يكون pkcs12_data سلسلة بايت تحتوي على بيانات ثنائية ، بينما قد يكون password سلسلة بايت أو سلسلة 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

يبدو لي أن مناقشة PKCS # 12 خارج نطاق المشكلة الأولية ، نظرًا لأن القضية المعنية هي ما إذا كان يجب أن تدعم الطلبات PKCS # 12 محليًا. سأقوم بالتصويت عليه ، لكن من الواضح أن الأمر متروك للأشخاص المسؤولين.

ومع ذلك ، كحل بديل لا يتطلب ملفات مؤقتة غير مشفرة ، تحتوي طريقة OpenSSL.crypto.dump_privatekey على معلمة عبارة مرور اختيارية ، لذلك يمكنك الحصول على نسخة من المفتاح الخاص المشفر بتنسيق PEM بهذه الطريقة. سيؤدي ذلك إلى تقليل هذا إلى مشكلة PEM المشفرة التي بدأنا بها.

بدلاً من ذلك ، يمكنك أيضًا كتابة اختراق مشابه للذي اقترحته قبل استخدام طريقة use_privatekey OpenSSL.SSL.Context . من أعلى رأسي (لم يتم اختباره) شيء من هذا القبيل

# 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

ثم استخدم فقط requests.get وما إلى ذلك دون تحديد شهادة على الإطلاق ، نظرًا لأنه تم التعامل معها بالفعل في المنشئ.

مراجعة هذا الموضوع الآن. إعادة صياغة الأصل:

بالنظر إلى شهادة عميل مشفرة بتنسيق PEM ، هل يمكن للطلبات التعامل مع توفير كلمة مرور؟

نظرًا لأن هذا في libs القياسية الحالية ، سيكون من الرائع دمج هذا الخيار. سيكون هذا مفيدًا للغاية لاعتبارات أمان المؤسسة (حيث يتم تشفير شهاداتنا ، ويقصد بها أن تظل كذلك).

في هذه المرحلة ، يمكن القيام بذلك عن طريق تمرير سياق ssl مخصص إلى urllib3 باستخدام محول النقل. هذا يمكن أن يفعل ما يسمح به سياق مكتبة SSL القياسي. يمكنك مشاهدة مثال على تمرير سياق مخصص هنا .

تمكنت من استخدام .pfx و. p12 مع الطلبات عن طريق تحويلها إلى ملف .pem باستخدام ملف مؤقت. انظر https://gist.github.com/erikbern/756b1d8df2d1487497d29b90e81f8068

إذا كان هناك أي اهتمام ، يمكنني تقديم بيان عام. سيكون من الرائع تجنب الملف المؤقت ومدير السياق. دعني اعرف.

ليس من المحتمل أن يتم دمج هذا ، أخشى ، لكن لاحظ أنه يمكنك الآن تمرير سياق PyOpenSSL مباشرة إلى الطلبات عبر محولات النقل ، لذلك قد تجد أنه يمكنك التحايل على هذه المشكلة.

ليس من المحتمل أن يتم دمج هذا ، أخشى ، لكن لاحظ أنه يمكنك الآن تمرير سياق PyOpenSSL مباشرة إلى الطلبات عبر محولات النقل ، لذلك قد تجد أنه يمكنك التحايل على هذه المشكلة.

آسف لكونك مرتبكًا ولكن هل تقول إن دعم pfx / p12 بشكل عام من المحتمل ألا يتم دمجه؟ (بافتراض أنه تم بالطريقة الصحيحة ، من خلال السياق وما إلى ذلك). يسعدني أن أجربها ولكن من الواضح أنها لا تستحق وقتي إذا لم يتم دمجها.

أعتقد أن "من غير المحتمل أن يتم دمجها" كان يتعلق بحل الملف المؤقت.

erikbern لأكون واضحًا ، يسعدني الاقتراب من أي حل يعمل باستمرار إلى حد ما

ومع ذلك ، فإن حل الملف المؤقت غير مقبول (كما هو مذكور بواسطةvog). هذا يعني أنه من غير المحتمل أن يعمل دعم PKCS # 12 مع المكتبة القياسية ، حيث أن وحدة المكتبة القياسية ssl لا تعرض أي دعم لها ، وبالتالي لن يتم دعمها في جميع تكوينات الطلبات.

يبدو جيدا. أوافق أيضًا على أن ملف temp سيئ نظرًا لوجود خطر أمني في تخزين المفاتيح التي تم فك تشفيرها على القرص. قد نلقي نظرة عليه الأسبوع المقبل. نشكرك على التنبيهات حول الوحدة النمطية ssl - إذا كان القيد خارج requests فمن الواضح أنه يصبح أكثر تعقيدًا

نظرت إليه و ssl حدة أضافت cadata حجة حيث يمكنك تمرير البيانات بيم كسلسلة الخام: https://docs.python.org/3/library/ssl.html # ssl.SSLContext.load_verify_locations

سيتعين علينا تصحيح urllib3 في مجموعة من الأماكن لإنجاح هذا الأمر ، لذلك قد أبدأ من هناك

erikbern للتوضيح ، سيعمل أي حل SSLContext مهيأ بشكل مناسب إلى urllib3 باستخدام TransportAdapter .

يبدو أن https://github.com/kennethreitz/requests/issues/2519 مطابق لهذه المشكلة ، لذا ربما ينبغي دمجها

أي تحديث بشأن هذه المشكلة أحاول استخدام شهادة عميل مشفرة بكلمة مرور وغير قادرة على تشغيلها. هل يجب أن أبحث عن خيارات أخرى غير الطلبات؟ هل يمكنك الرد في أسرع وقت ممكن.

هل نوثق هذا؟ أشعر أن هذه هي الميزة الأكثر طلبًا لدينا.

أعتقد أن هذا الموضوع بدأ في عام 2013 ولم أجد أي حل موضح حتى النهاية. هل قدمتم يا رفاق خيارًا لتوفير كلمة المرور؟ أم أن هذا لا يزال قيد التقدم؟

أحاول استخدام الطلبات في منتج أمان التطبيق الذي أقوم بإنشائه. لذا فإن أي مؤشرات ستكون مفيدة

نعم ، لقد قرأت هذا التعليق ، هذا عمل حوله ولكن في حالتي لا أريد تحويله إلى ملفين سيرتين لأن ذلك سيتعين عليه القيام به خارج طلبي. علاوة على ذلك ، نستخدم قبوًا مثل شيء لتخزين كلمة المرور لملف pem. المشفر.

يتم استرداد كلمة المرور هذه ديناميكيًا بواسطة التطبيق في وقت التشغيل لذلك لا يوجد ترميز ثابت.

تضمين التغريدة

@ kennethreitz لا ، لم

AnoopPillai نعم ، هذا يعمل بشكل جيد. تحتاج فقط إلى استخدام بعض الخطافات منخفضة المستوى. في هذه الحالة ، نسمح لك بتمرير SSLContext إلى urllib3 مباشرة على مستوى محول النقل. يتيح لك هذا الوصول إلى الوظائف الأساسية التي ستتيح لك توفير وظيفة عبارة المرور أو عبارة المرور. هذه هي الطريقة التي نوصي بها بدعم هذا.

AnoopPillai الحل البديل باستخدام ملف مؤقت وجدته مفيدًا: https://gist.github.com/erikbern/756b1d8df2d1487497d29b90e81f8068

شكرًا Lukasa لإخباري بأن هناك طريقة للقيام بذلك.
أنا جديد جدًا على Python وأستخدم الإصدار 3.6. هل يمكن أن ترشدني إلى حيث يمكنني العثور على خيار مثل الأصفار لتمرير كلمة مرور شهادة العميل.
Erikbern لم أذهب من خلال حل الملف المؤقت حتى الآن

AnoopPillai ستريد load_cert_chain .

Lukasa هل تمانع في توثيقه؟ يجب أن يستغرق بضع دقائق فقط (أفكر في القسم المتقدم ، أو ربما في قسم متقدم جديد)

آسف يا رفاق ، قد يكون افتقاري لخبرتي مع Python هو السبب ولكني غير قادر على تعديل الكود الذي أوضحه Lukasa أعلاه. الكود الخاص بي هو:

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()

وأتلقى خطأ
TypeError: حصلت create_urllib3_context () على وسيطة كلمة رئيسية غير متوقعة 'load_cert_chain'

هذا خطأ ، نعم. تريد استدعاء create_urllib3_context والحصول على قيمة الإرجاع الخاصة به ، ثم استدعاء load_cert_chain على الكائن المرتجع. حاول اللعب بهذه الوظائف في المترجم التفاعلي لترى كيف تعمل.

لا يحتوي urllib3..util.ssl_.py المثبت على جهاز Mac الخاص بي على أحدث خيار لكلمة المرور.
هذا هو الكود

    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)

خيار كلمة المرور مفقود. كيف أقوم بتحديث ssl_.py للحصول على أحدث إصدار؟

تضمين التغريدة قم باستدعاء الوظيفة بدون وسيطات ، ثم قم باستدعاء load_cert_chain على الكائن الذي تم إرجاعه. لا تحتاج إلى تغييرات في urllib3.

لنكون واضحين ، مثل هذا:

ctx = create_urllib3_context()
ctx.load_cert_chain(your_arguments_here)

دعونا نوثق هذا :)

@ erikbern لقد جربت حل tempfile لكنني حصلت على خطأ المتابعة:

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')],)",),))

أدناه هو الرمز الخاص بي:

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())

آسف ، من الصعب معرفة سبب كسر هذا التعليق. لقد استخدمته لمجموعة من التطبيقات ولم أواجه أي مشاكل

Lukasa لقد جربت تغيير هذا الرمز (تم لصق الرمز أدناه) وانتهى بي الأمر بنفس الخطأ الذي تلقيته باستخدام طريقة 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 يمكن أن تكون مشكلة في الإعداد على الكمبيوتر المحمول الخاص بي. أستخدم نظام التشغيل 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: 

هل تعتقد بوجود خطأ في الشهادة؟

ما هو ناتج python -m requests.help ؟

Lukasa الإخراج هو:

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

الرجاء إزالة علامة الاستفهام من سطر الأوامر الخاص بك.

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
}

لذا فإن الخطأ الذي تحصل عليه ناتج عن عدم قدرتنا على التحقق من صحة شهادة TLS للخادم. يبدو أن certifi و OpenSSL على حق ، لذلك أفترض أن الخادم يعمل بشكل سيء. ما الخادم الذي تحاول الوصول إليه؟

يتم نشر التطبيق على Cloud AWS. ولكن عندما نطلق على API ، فإنه ينتقل أولاً إلى OSB الذي يصادق على الشهادة ثم يوجه الطلب إلى AWS.
أستخدم نفس الشهادة وباستخدام ساعي البريد أو رمز روبي الخاص بي ، تعمل واجهة برمجة التطبيقات بشكل جيد

هل تحتاج إلى شهادة جذر معينة؟ هل يمكنك تقديم اسم المضيف الذي يتم الوصول إليه من أجلي؟

عنوان URL للمضيف بدون المسار هو https://credit-cards-accounts-qa.kdc.capitalone.com
هذه نقطة نهاية داخلية

أجل ، لذا لا يمكنني رؤية ما يحدث هناك. هل يمكنك تشغيل openssl s_client -showcerts -connect credit-cards-accounts-qa.kdc.capitalone.com:443 وتقديم الناتج الكامل؟

تم الحذف

يبدو هذا إلى حد كبير أنك لا تستخدم شهادة جذر موثوق بها عالميًا. أين هي شهادة الجذر لتلك الخدمة؟

أنا لا أستخدم أي شهادات أخرى. لست متأكدًا مما إذا كانت هناك أي شهادة جذر تستخدم خلف الكواليس ، فهل هناك طريقة بالنسبة لي لمعرفة ذلك؟

نعم ، ستخبرك أدوات مطور Chrome بسلسلة الشهادات الكاملة التي تستخدمها.

ربما لا ترغب في نشر بعض الشهادات الداخلية عبر الإنترنت ليراها أي شخص ...

erikbern هذه معلومات عامة. يمكنك تحقيق نفس النتيجة عن طريق تشغيل نفس الأمر.

SethMichaelLarson من ملفerikbern على GitHub "ضابط ترول الرئيسي". ربما كانوا يتصيدون فقط؟

تضمين التغريدة لم أكن أعرف من كنت أتحدث. تقدم! 🙇

لا أستطيع رؤية أي شيء باستثناء شهادة SHA-1 عندما أركض من ساعي البريد
قد أحتاج إلى إضافة هذا بطريقة ما إلى Pycharm

إذا كنت تتصفح موقع الويب في Chrome حرفيًا ، فسيكون ذلك كافيًا.

SethMichaelLarson تشغيل ما الأمر؟ لمعلوماتك ، تم حذف التعليق الآن ولكن كان هناك فقاعة كاملة لشهادة BEGIN هنا في وقت سابق ... afaik لا تريد مشاركة ذلك عبر الإنترنت

erikbern كان هذا فقط المفتاح العام

الشهادات هي بيانات عامة ؛ يتم إرسالها بنص عادي عبر الشبكة عند كل محاولة اتصال.

ذهبت إلى سلسلة الشهادات ووجدت فقط Sha-1 cert و pem. الذي أستخدمه للوصول إلى واجهة برمجة التطبيقات

AnoopPillai حصلت على رمز المثال الخاص بك من 1 سبتمبر يعمل بدون مشكلة باستخدام ملف pem من جانب العميل بكلمة مرور. يبدو أن المضيف يستخدم شهادة عادية. مع Lukasa شكرا جزيلا!

ما زلت أواجه مشكلات للأسف ، حتى مع طريقة Temp File. يمكنني استخدام .pfx في Google Postman وليس لدي أي مشاكل في المصادقة (لذلك أعرف أن بيانات الاعتماد الخاصة بي تعمل) ، لكنني ما زلت أحصل على 401s مع Python. لسوء الحظ ، لم يقدم موظف الدعم من الشركة التي أتعامل معها الكثير من المساعدة - هل لدى أي شخص أي اقتراحات لاستكشاف الأخطاء وإصلاحها؟

في هذه المرحلة ، لست متأكدًا حقًا من مكان البحث عن المشكلة نظرًا لأن أشخاصًا آخرين يبلغون عن النجاح باستخدام طريقة Temp File وما زلت لم أسمع أي شيء من فريق إدارة الشهادات.

سنكون ممتنين لأي نصيحة - يرجى إعلامي إذا كان بإمكاني تقديم أي معلومات إضافية لتسهيل ذلك.

شكرا :)

مجرد اقتراح ، هل حاولت تحويل PFX إلى PEM؟ أيضًا ، إذا كان الخادم يستخدم أيضًا اسم مستخدم / كلمة مرور ، فستحتاج إلى إضافة طلب الحصول / النشر باستخدام المصادقة = (). لقد كنت أستخدم الأسلوب class DESAdapter(HTTPAdapter) أعلاه لعدة أسابيع الآن بدون مشكلة ، باستخدام ملف PEM محمي بكلمة مرور.

ideasean لا يزال يتم الحصول على بيانات اعتماد غير صالحة. يجب أن أشير إلى load_cert_chain في ملف .pem تم إنشاؤه بواسطة الدالة pfx_to_pem المكتوبة لأسلوب Temp File ، أليس كذلك؟ يحتوي على المفتاح الخاص والشهادة فيه.

نظرًا لأن ملف .pfx يعمل مع Postman ولكنه لن يتم المصادقة هنا ، فهل يعني ذلك حدوث خطأ ما في عملية التحويل؟

لم أستخدم طريقة الملف المؤقت. لقد استخدمت نهج DESAdapter إلى حد كبير كما هو مكتوب في مشاركة AnoopPillai في 1 سبتمبر أعلاه بدءًا من -

لقد حاولت تغيير هذا الرمز (الكود الذي تم لصقه أدناه) وانتهى بي الأمر بنفس الخطأ الذي تلقيته باستخدام طريقة tempfile.

لا يمكنني التحدث عن عملية التحويل ، ولكن ربما يكون الاختبار الجيد هو محاولة استخدام ملف pem المحول مع Postman؟

لاحظ أيضًا أنني استخدمت الأسلوب أعلاه لأن ملف pem الخاص بي كان مشفرًا / محميًا بكلمة مرور ، وطلبات Python لا تدعم ذلك حاليًا. إذا انتهى الأمر بأن pem الخاص بك غير محمي بكلمة مرور ، فيجب أن تكون قادرًا على استخدام الطلبات الأصلية لكل رابط (ولكن بعد ذلك سيكون لديك شهادة غير محمية على نظام الملفات الخاص بك).

ideasean لقد كسرت ملف .pfx وفقًا لهذه الطريقة وحصلت على ملف .pem بسمات الحقيبة والشهادة بالإضافة إلى ملف .pem بسمات الحقيبة ومفتاح خاص مشفر.

ما زلت أحصل على بيانات اعتماد غير صالحة ، أعتقد أنني سأحاول وضع الشهادات على Postman ومعرفة ما إذا كانت تعمل ولكن لا يمكنني معرفة سبب عدم تمكني على ما يبدو من فك ضغط ملف .pfx هذا بشكل صحيح

لقد جربت أيضًا الأمر openssl openssl pkcs12 -in <my_pfx>.pfx -out certificate.cer -nodes ، ولا يزال يعطيني خطأ 401 عندما أتغير إليه على النحو التالي: context.load_cert_chain('certificate.cer')

لقد قمت بتثبيت .cer و Postman المذكور أعلاه لا يطلب حتى استخدامه عندما أقوم بإجراء استدعاء API (على عكس النافذة المنبثقة عندما يطلب استخدام .pfx) ، لست متأكدًا من كيفية استخدام هذه الشهادة المحددة. نظرًا لعدم وجود لوحة "شهادات" في الإعدادات مثل المستندات التي تشير إلى وجودها.

ربما تستخدم إصدار المتصفح من Postman ، والذي لا يتضمن لوحة الشهادات ، أو تعطيل التحقق من ssl وما إلى ذلك. جرب العميل الكامل لتغيير إعدادات الشهادة. قد ترغب في متابعة هذه المناقشة حول موضوع مختلف بعد ذلك ، لأننا بعيدون قليلاً عن الموضوع.

شاهد @ mkane848 تعليقك الأصلي حيث كنت تحصل على ValueError: String expected . قد ترغب في التحقق من https://github.com/pyca/pyopenssl/issues/701 و https://github.com/shazow/urllib3/issues/1275.

أستخدم pem الخاص بي مع كلمة مرور باستخدام هذا:

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

لمعلوماتك ، لقد قمت للتو بتنفيذ دعم PKCS # 12 لـ requests كمكتبة منفصلة:

الكود هو تطبيق نظيف : فهو لا يستخدم ترقيع القرود ولا الملفات المؤقتة. بدلاً من ذلك ، يتم استخدام TransportAdapter المخصص ، والذي يوفر SSLContext مخصصًا.

نرحب بأي ملاحظات وتحسينات!

بالطبع ، أتمنى أن يوفر requests هذه الوظيفة مباشرةً ، ولكن حتى نصل إلى هناك ، ستخفف هذه المكتبة من الألم.

سيكون من الرائع جدًا أن نفعل هذا ببساطة:

~~~
cert = ("cert.pem"، "key.pem"، "somepassphrase") # شهادة / مفتاح منفصل

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

~~~

... حتى لو كان يعمل فقط على python 3.3+. سيكون هذا فقط إضافة ثانوية لسطح API.

AFAICS ، قد يعني هذا تغييرًا بسيطًا في urllib3 بحيث يقبل HTTPSConnection وسيطة اختيارية password ؛ يتم تمرير هذا من خلال ssl_wrap_socket ، وينتهي بـ:

~إذا سيرتفيلي:إذا لم تكن كلمة المرور لا شيء:Context.load_cert_chain (ملف سير ، ملف مفتاح ، كلمة مرور)آخر:Context.load_cert_chain (ملف سيرد ، ملف مفتاح)~

بعد ذلك سيكون متوافقًا مع الإصدارات السابقة ، مما يثير استثناءً فقط إذا حاولت استخدام عبارة مرور المفتاح الخاص على نظام أساسي قديم لا يدعمه.

لاحظ أن المحول contrib/pyopenssl.py يدعم بالفعل هذه الوسيطة الإضافية لـ load_cert_chain ، وكذلك بيثون 2.7 .


جانباً: أنا أستخدم AWS KMS لإدارة البيانات "السرية" ، لذلك سأقوم بتحميل كلمة مرور المفتاح في وقت التشغيل من KMS ، وليس برمجتها في التطبيق.

أنا شخصياً لن أعارض هذا التغيير ، حيث أعتقد أنه سيحسن بشكل كبير واجهة المستخدم الخاصة بنا للعديد من المستخدمين في جميع المجالات.

@ sigmavirus24 أي أفكار؟

candlerbkennethreitz فإنه سيكون مقبولا لتشمل حالة PKCS # 12 إلى أن API كذلك؟

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

يمكن أن يكون التمييز إما عن طريق امتداد الملف ( *.p12 مقابل *.pem ) ، أو بالنظر إلى البايتات الأولى من هذا الملف.

ليس لدي مشكلة في السماح للطلبات بأخذ pkcs # 12 ، طالما أنه يمكن إجراؤها بأمان - وفي رأيي ، يمنع ذلك كتابة المفتاح الخاص المستخرج إلى ملف مؤقت.

البحث في Googling لـ Python pkcs # 12 ، أجد:

  • رمز شخص ما يكتب المفتاح الخاص
  • بعض الآخر كود الذي أعتقد أنه يعتمد على pyOpenSSL لقراءة في PKCS # 12. تقوم بإرجاع الشهادة والمفتاح كعناصر بيانات.

لذلك ، عند القيام بذلك ، أعتقد أنه سيكون من الضروري ربط الأشياء بطريقة يتم فيها تمرير المفتاح / الشهادة نفسها إلى OpenSSL ، وليس أسماء الملفات التي تحتوي على تلك الأشياء. هذا يبدو وكأنه تغيير أكبر بكثير.

إذا كان هذا صعبًا جدًا ، فهذا يعني فقط أنه يتعين على المستخدم تحويل pkcs # 12 إلى PEM off-line ، وهو أمر بسيط جدًا (ويمكن توثيقه).

candlerb كما كتبت في تعليقي السابق (https://github.com/requests/requests/issues/1573#issuecomment-348968658) ، لقد أنشأت بالفعل تطبيقًا نظيفًا يتكامل جيدًا مع requests .

لذلك تم حل المشكلات التي تصفها بالفعل.

في الوقت الحالي ، يضيف تطبيقي وسيطات الكلمات الرئيسية الجديدة pkcs12_* ، للبقاء بعيدًا عن الطريق قدر الإمكان.

لكنني أعتقد أنه يجب دمجها في وسيطة الكلمة الرئيسية cert بدلاً من ذلك ، وسؤالي هو:

  • هل هذا مقبول بشكل عام؟
  • هل سيقبل اقتراحي الملموس cert=('keycert.p12', None, 'somepassphrase') ؟
  • كيف يمكننا التمييز بين PKCS # 12 و PEM؟ (حسب لاحقة اسم الملف أو حسب محتويات الملف؟)

(علاوة على ذلك ، أفضل أن أرى ذلك في requests بدلاً من مكتبتي requests_pkcs12 المنفصلة. ولكن نظرًا لعمر هذه المشكلة ، لدي أمل ضئيل في أن يتم تشغيل هذا في أي وقت قريبًا. ومع ذلك ، إذا كان هناك بيان ملموس حول نوع التنفيذ المطلوب تحديدًا ، فربما يمكنني تعديل التنفيذ وفقًا لذلك واقتراح طلب سحب.)

إذن ، هناك بعض الأشياء:

  1. لا أعتقد أننا يجب أن نأخذ الكلمة الأساسية للشهادة ونوسعها على هذا النحو. إنها بيانات منظمة بشكل ضمني ، والأشخاص مرتبكون بالفعل من خلال المجموعات في الكلمة الرئيسية files . أعتقد أن الاستمرار في نمط معروف سيئ هو حماقة.

  2. أعتقد أنه إذا كان هناك أي شيء ، فيجب تعديل محول pkcs12 وتحديثه في حزام أدوات الطلبات. أعتقد أنه سيكون من الأفضل تعديله لإنشاء ssl_context مرة واحدة بدلاً من تخزين كلمة مرور pkcs12 في الذاكرة على هذا الكائن.

أعتقد أنه لا يزال هناك عمل آخر يحتاج إلى القيام به قبل أن نتمكن من التعامل مع هذا في الحالة الأكثر عمومية بغض النظر عما يتضمن ذلك تحديد واجهة برمجة التطبيقات المناسبة لهذا للطلبات 3.0.

@ sigmavirus24 شكرا لملاحظاتك.

  1. حسنًا ، فلنحتفظ بالكلمات الرئيسية المنفصلة pkcs12_* .
  2. نعم ، هذا بالتأكيد يستحق التحسين. لقد قمت بإنشاء إدخال تعقب المشكلات لذلك: https://github.com/m-click/requests_pkcs12/issues/2

كيف سيتم تضمين فئة PKCS # 12 TransportAdapter في requests ؟ هل ستتم إضافة هذه الفئة ببساطة إلى requests ، أم أن هناك طريقة أخرى لتضمينها على مستوى "أعمق" ، بحيث يمكن استخدامها بدون أي أغلفة request()/get()/... وبدون الحاجة إلى تحميل ذلك صراحة مشترك كهربائي؟

تحتاج منظمتي إلى استخدام شهادات PKCS12 وهي على استعداد لإجراء التحسينات اللازمة على مكتبتك من أجل القيام بذلك. يعتبر فك تشفير ملفات .p12 إلى ملفات .pem مخاطرة كبيرة ويضيف خطوة إضافية للتعامل معها. نود إضافة وظائف لإنشاء وتقديم ssl_context مناسب لجلسة معينة. هل لا تزال هذه الوظيفة التي سيكون فريقك على استعداد لقبولها بافتراض تنفيذها بشكل صحيح؟

مجرد تذكير سريع: لقد تم بالفعل توفير تطبيق نظيف من قبل شركتنا ، ولكن كمحول منفصل: https://github.com/m-click/requests_pkcs12

لا تتردد في إعادة تنسيقه إلى طلب سحب للطلبات نفسها.

على طول الطريق ، قد ترغب في إصلاح مشكلة بسيطة: لا يجب الاحتفاظ بـ ssl_context في الذاكرة لجلسة كاملة ، ولكن في أقرب وقت ممكن ، فقط لاتصال واحد محدد. أنظر أيضا:

في حالة إصلاحه على طول الطريق ، سيكون من الجيد تقديمه كطلب سحب صغير إلى https://github.com/m-click/requests_pkcs12 بالإضافة إلى الطلبات نفسها.

بهذه الطريقة ، سيستفيد جميع الأشخاص الذين يستخدمون مكتبة requests_pkcs12 الآن تلقائيًا من هذا التحسين أيضًا ، دون الحاجة إلى التبديل إلى واجهة برمجة التطبيقات الجديدة (المحسّنة آنذاك) للطلبات نفسها.

نعم ، https://github.com/m-click/requests_pkcs12 عملت معي وفعلت بالضبط ما أردت أن تفعله. شكرا جزيلا vog ! آمل أن تتمكن الطلبات من دعم ذلك في النهاية.

سأشكر أيضًا المستودعات غير الآمنة مثل S3 في حالتي. نأمل أن يشق هذا طريقه إلى requests .

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

justlurking picture justlurking  ·  3تعليقات

jakul picture jakul  ·  3تعليقات

jake491 picture jake491  ·  3تعليقات

JimHokanson picture JimHokanson  ·  3تعليقات

NoahCardoza picture NoahCardoza  ·  4تعليقات