web-dev-qa-db-ja.com

pythonリクエストを使用したWindowsでのSSL失敗

非常に長い投稿についてお詫びしますが、私は本当に徹底しようとしています...

リモートサーバーから操作され、さまざまな種類のOS(Linux、MacOS、Windows)で実行されているさまざまな環境モデル間でデータを交換するためのブリッジとして機能する専用のWebサイトがあります。基本的に、各サーバーはWebサイトにデータファイルをアップロード/ダウンロードでき、ファイルは別のサーバーの異なるモデルでさらに処理するために使用されます。

Webサイトにはいくつかの基本的な保護機能があります(IPフィルタリング、パスワード、およびLetsEncrypt証明書を使用したSSL)。すべてのリモートサーバーは、サイトにアクセスし、作成したシンプルなWebインターフェイスを介してデータをアップロード/ダウンロードできます。

ここでは、簡単なpython(2.7)デーモン(requestsモジュールに基づく)を使用して、交換の一部を自動化しようとしています。デーモンは特定のフォルダを監視し、コンテンツをWebサイトにアップロードします。

このデーモンは、Windows 7 Enterprise 64ビットを実行しているサーバーを除き、すべてのリモートサーバーで正常に動作します。このサーバーにはPython 2.7.13がインストールされており、次のパッケージが含まれています:DateTime(4.1.1)、psutil(5.2.0)、pytz(2016.10)、requests(2.13.0)、zope)。インターフェース(4.3.3)。

このサーバーからは、SSL接続はWebブラウザーを介して正常に機能しますが、デーモンは常に以下を返します。

raise SSLError(e, request=request)
requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:661)

これまでに試したことは次のとおりです。

  • verify = falseを設定します。これは正常に機能しますが、最終的な本番環境では使用できません。
  • デーモンが動作する別のサーバーから証明書をコピーし、verify =(証明書ファイルの名前)を設定します(成功しません)
  • 'User-agent'を、Webブラウザーで接続が行われたときにWebサイトのWindowsマシンから取得したものとまったく同じ文字列に設定します(成功しません)。

問題を解決するために、Windowsサーバーで他にどのような設定を確認する必要がありますか?どういうわけかブラウザのSSL接続は許可するが、pythonデーモンをブロックするファイアウォール設定にすることはできますか?

[〜#〜]更新[〜#〜]
エラーを生成していたWindowsリモートサーバーを実行している組織は、すべてのSSL証明書をプロキシレベルで置き換えます。
IT担当者は、プロキシ設定の「パススルー」サイトのリストにWebサイトのURLを追加することで問題を解決しました。

これは機能し、現時点では問題ありません。ただし、Pythonで直接証明書の置換を処理できたかどうかは疑問です...

12
user6357781

Requests ライブラリを取得して、Pythonの組み込みsslモジュールを使用して、HTTP接続のSSL部分を作成することができます。 Requestsが使用する rllib3 utils がPython SSLContext をそれらに渡すことを許可するため、これは実行可能です。

ただし、これは、以前のWindowsアクセスに基づいてトラストストアにすでにロードされている必要な証明書に依存する場合があることに注意してください( このコメント を参照)

次にいくつかのサンプルコードを示します(これには、最新バージョンのリクエストが必要です。2.18.4で動作します)。

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

class SSLContextAdapter(HTTPAdapter):
    def init_poolmanager(self, *args, **kwargs):
        context = create_urllib3_context()
        kwargs['ssl_context'] = context
        context.load_default_certs() # this loads the OS defaults on Windows
        return super(SSLContextAdapter, self).init_poolmanager(*args, **kwargs)

s = requests.Session()
adapter = SSLContextAdapter()
s.mount('https://myinternalsite', adapter)
response = s.get('https://myinternalsite')
14
David Fraser

リクエストは、ブラウザのようにWindowsルートCAストアを使用しません。

ドキュメントから:デフォルトでは、リクエストには、Mozillaトラストストアから提供された、信頼する一連のルートCAがバンドルされています。ただし、これらはリクエストのバージョンごとに1回だけ更新されます。

この信頼できるCAのリストは、REQUESTS_CA_BUNDLE環境変数を使用して指定することもできます。

あなたは文字通りこれを行うことができます:

cafile = 'cacert.pem' # http://curl.haxx.se/ca/cacert.pem
r = requests.get(url, verify=cafile)

または、CA証明書がパブリックエンティティによって署名されている場合は、certifiを使用できます。

1
Artagel