Python リクエストで SSL セキュリティ証明書チェックを無視する
安全な SSL 証明書を使用せずに URL にアクセスすると、HTTP 要求が URL に送信されるときに例外警告が発生します。 多くの場合、これらの URL の SSL 証明書は期限切れになり、あらゆる種類のセキュリティの問題が発生します。
情報が機密でない場合、プログラムが Python で request
を使用すると、これらの警告を抑えることができます。 この記事では、requests
を使用してセキュリティ証明書のチェックを無効にする複数の方法を紹介します。
SSL セキュリティ チェックの背後にある理由と失敗する理由を理解する
プログラムが Python requests
を使用して、SSL 証明書の有効期限が切れている URL からリクエストを取得すると、2つの例外が発生します。 以下のプログラムは、それらの例外が何であるかを表示します。
シナリオ 1
このプログラムは、SSL コミュニティによって提供された、期限切れのセキュリティ証明書をテスト目的で使用する URL を使用します。 SSL
セキュリティ例外は、期限切れの SSL
証明書を持つ URL でのみ発生することに注意してください。
Python の リクエスト
は、有効な SSL
証明書または取り消された証明書を持つ URL で例外を発生させません。 そのため、この記事では主にセキュリティ証明書の有効期限が切れている URL に焦点を当てます。
以下の例は、最初の行で requests
をインポートする簡単なプログラムを示しています。 プログラムの 2 行目は、post
リクエストを URL に送信して、出現する 'bar'
を 'baz'
に変更します。
post
リクエストを URL に送信するために行われ、プログラム内でそれ以外の意味を持ちません。
import requests
requests.post(url="https://expired-rsa-dv.ssl.com/", data={"bar": "baz"})
この Python スクリプトを実行すると、SSLError
例外がスローされます。
....
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='expired-rsa-dv.ssl.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:841)'),))
これは、requests
を使用してセキュリティ証明書のチェックを無効にする方法を学習する際に考慮すべき最初の例外です。
シナリオ 2
このプログラムは、verify=False
を使用して SSL
証明書の検証をオフにし、requests
を使用してセキュリティ証明書のチェックを無効にします。
import requests
requests.post(url="https://expired-rsa-dv.ssl.com/", data={"bar": "baz"}, verify=False)
requests
ライブラリは、SSL
証明書の検証をオフにできるように構築されていますが、プログラムは期限切れの SSL
証明書を持つリンクで別の例外をスローします。
InsecureRequestWarning: Unverified HTTPS request is being made to host 'expired-rsa-dv.ssl.com'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
InsecureRequestWarning,
これらの 2つの例外は、requests
を使用してセキュリティ証明書のチェックを無効にするために処理する必要があります。
Python で SSL セキュリティ チェックを無視する
このセクションでは、requests
を使用してセキュリティ証明書のチェックを無効にするか、問題を解決するさまざまな方法について説明します。 すべてのメソッドには目的があります。
requests
ライブラリのモンキー パッチを作成する
サードパーティのライブラリでセキュリティ チェックを無効にする必要がある場合は、requests
ライブラリに モンキー パッチを適用 できます。 コンテキスト マネージャーは、requests
を使用したセキュリティ証明書のチェックを無効にするためのパッチ適用に使用されます。
requests
がパッチされた後、verify
フィールドにはデフォルトで False
値が与えられ、警告が抑制されます。 前のセクションのシナリオ 2 で説明したように、verify=false
を使用すると、別の警告が発生します。
このパッチは、例外処理ブロックを追加して、requests
を使用したセキュリティ証明書のチェックを無効にし、警告を抑制します。 次の例を使用すると、理解しやすくなります。
以下のプログラムは requests
ライブラリにパッチを当てます。 このコードが何をするのかを理解しましょう。
輸入品:
warnings
: このライブラリ パッケージはExceptions
ライブラリのサブパッケージです。contextlib
: この Python ライブラリは、requests
ライブラリにパッチを適用するために使用されます。requests
: Python の requests ライブラリ パッケージ。urllib3
: Python で HTTP リクエストと URL を処理するモジュールです。 このライブラリは、期限切れのSSL
証明書に対して例外を発生させるサブモジュールInsecureRequestWarning
をインポートするために使用されます。
パッチ:
最初に、プログラムは requests
ライブラリのデフォルトの環境設定を変数 old_merge_environment_settings
に保存します。 この変数は、開いているアダプターが閉じられた後、requests
をデフォルトの状態に戻すために使用されます。
old_merge_environment_settings = requests.Session.merge_environment_settings
メソッド no_ssl_verification
が作成され、@contextlib.contextmanager
で装飾されます。 新しい変数 opened_adapters
が作成され、set()
がそれに割り当てられます。
セットは、アイテムを順序付けされていない形式で格納するデータ型です。
@contextlib.contextmanager
def no_ssl_verification():
opened_adapters = set()
no_ssl_verification
メソッド内で、別のネストされたメソッド merge_environment_settings
が作成されます。 このメソッドには、requests
モジュールの merge_environment_settings
に似た 6つのパラメーターがあり、元のモジュールのパッチとして機能します。
def merge_environment_settings(self, url, proxies, stream, verify, cert):
メソッド内で、opened_adapters
変数は、パラメーター url
からの一致するアダプター ペアで更新されます。 すべての接続は、このステップで返されるいくつかの一致するアダプター ペアで行われます。
検証は接続ごとに 1 回しか行われないため、終了後に開いているすべてのアダプターを閉じる必要があります。 そうでない場合、verify=False
の効果は、このコンテキスト マネージャーが終了した後も持続します。
def merge_environment_settings(self, url, proxies, stream, verify, cert):
opened_adapters.add(self.get_adapter(url))
コードの次の行を理解するには、記事の最初のセクションを覚えておくことが重要です。 期限切れの SSL
証明書を使用して URL で requests.post
関数を使用すると、2つの例外がスローされました。
最初の例外は、True
値で設定された verify
によって引き起こされました。 verify
フィールドは切り替え可能でしたが、False
値を与えることができました。
2 番目の例外は、変更不可能なエンティティであり、プログラムが接続を確立できなくなりました。
以下のコードは、この問題を解決するために、verify
フィールドをデフォルトで False
値を持つように変更します。 このステップを実行するために新しい変数 settings
が作成され、変数 old_merge_environment_settings
からのデータが割り当てられます。
データが変数 settings
内に保存されると、verify
フィールドは False
になります。
これにより、verify
のデフォルト値が変更されます。 最後に、この変数が返されます。
settings = old_merge_environment_settings(self, url, proxies, stream, verify, cert)
settings["verify"] = False
return settings
更新された merge_environment_settings
メソッドからのデータは、関数 requests.Session.merge_environment_settings
に割り当てられます。 これにより、フィールド verify
がデフォルトで False
値を持つことが保証されます。
requests.Session.merge_environment_settings = merge_environment_settings
最初の例外を処理しました。 変更できない 2 番目の例外は、例外処理ブロックを使用して解決されます。
ここでコードが何をするかを理解しましょう。
最初に、try
ブロック内で、発生したすべての警告をキャッチする with
ブロックが作成されます。 この with
ブロック内では、warnings.simplefilter
関数を使用して ignore
値を urllib3
サブモジュール InsecureRequestWarning
に与えます。
インポートのセクションで学んだように、InsecureRequestWarning
サブモジュールは期限切れの SSL
証明書に対して例外を発生させます。 ignore
値を割り当てると、2 番目に発生した例外がバイパスされます。
try:
with warnings.catch_warnings():
warnings.simplefilter('ignore', InsecureRequestWarning)
yield
finally
ブロック内では、old_merge_environment_settings
内に格納された元の設定が関数 requests.Session.merge_environment_settings
に割り当てられます。
プログラムを終了する前に、開いているすべてのアダプターを閉じる必要があるため、プログラム内で開いているアダプターの回数だけ反復する for
ループが作成されます。
すべてのアダプターは、関数 adapter.close()
を使用して、try-except
ブロックを使用して閉じられます。 except
ブロック内で、反復が渡されます。
for adapter in opened_adapters:
try:
adapter.close()
except:
pass
完全なコードを以下に示します。
import warnings
import contextlib
import requests
from urllib3.exceptions import InsecureRequestWarning
old_merge_environment_settings = requests.Session.merge_environment_settings
@contextlib.contextmanager
def no_ssl_verification():
opened_adapters = set()
def merge_environment_settings(self, url, proxies, stream, verify, cert):
opened_adapters.add(self.get_adapter(url))
settings = old_merge_environment_settings(
self, url, proxies, stream, verify, cert
)
settings["verify"] = False
return settings
requests.Session.merge_environment_settings = merge_environment_settings
try:
with warnings.catch_warnings():
warnings.simplefilter("ignore", InsecureRequestWarning)
yield
finally:
requests.Session.merge_environment_settings = old_merge_environment_settings
for adapter in opened_adapters:
try:
adapter.close()
except:
pass
Python でモンキー パッチを使用する
モンキー パッチは、no_ssl_verification()
メソッドを使用して呼び出すことができます。 このメソッドで送信されるリクエストはすべて、モンキー パッチの指示に従い、requests
を使用してセキュリティ証明書のチェックを無効にします。
例を見てみましょう。
メソッド no_ssl_verification
は with
ブロックの下で呼び出されます。 これにより、ブロック内でメソッドが実行され、コンパイラがブロックから出ると閉じます。
ブロック内で、期限切れの SSL
証明書を使用して、requests.get
呼び出しが URL に送信されます。 デフォルトの設定では、これにより例外がスローされますが、今回は requests.get
呼び出しが正常に送信されます。
requests
で別のリクエストが送信され、verify
フィールドが True
に設定されます。 デフォルトのシナリオとは異なり、今回はエラー例外はスローされません。
with no_ssl_verification():
requests.get("https://expired-rsa-dv.ssl.com/")
print("Modifications working Properly")
requests.get("https://expired-rsa-dv.ssl.com/", verify=True)
print("`Verify=true` has its meaning changed")
出力:
Modifications working Properly
`Verify=true` has its meaning changed
Verify=False
には、パッチをデフォルト設定にリセットするディレクティブが含まれていることがわかりました。 このフィールドが requests.get()
内で設定された場合、モンキー パッチはデフォルト設定にリセットされ、エラー例外をスローできるようになります。
requests.get("https://expired-rsa-dv.ssl.com/", verify=False)
print("It resets back")
出力:
connectionpool.py:1052: InsecureRequestWarning: Unverified HTTPS request is being made to host 'expired-rsa-dv.ssl.com'.
InsecureRequestWarning,
It resets back
requests
サブモジュール session
は、monkey パッチでも使用できます。
session
という名前の変数では、関数 requests.Session()
がロードされます。 session.verify
値は True
に設定されています。
with
ブロック内では、session.get()
関数を使用して get
リクエストを URL に送信し、verify
フィールドを True
に設定します。 print
ステートメントは、接続が確立された場合にメッセージを出力します。
session = requests.Session()
session.verify = True
with no_ssl_verification():
session.get("https://expired-rsa-dv.ssl.com/", verify=True)
print("Works in Session")
出力:
Works in Session
コンテキスト マネージャーが終了すると、このコードは、パッチが適用された要求を処理する開いているアダプターをすべて閉じます。 requests
はセッションごとに接続プールを維持し、証明書の検証は接続ごとに 1 回だけ行われるため、次のような予期しないイベントが発生します。
try:
requests.get("https://expired-rsa-dv.ssl.com/", verify=False)
except requests.exceptions.SSLError:
print("It breaks")
try:
session.get("https://expired-rsa-dv.ssl.com/")
except requests.exceptions.SSLError:
print("It breaks here again")
出力:
C:\Users\Win 10\venv\lib\site-packages\urllib3\connectionpool.py:1052: InsecureRequestWarning: Unverified HTTPS request is being made to host 'expired-rsa-dv.ssl.com'.
InsecureRequestWarning,
It breaks here again
urllib3
を使用して Python で警告を無効にする
requests
やモンキー パッチを使用せずにセキュリティ証明書のチェックを無効にする必要がある場合は、urllib3
を使用すると簡単な解決策が得られます。
requests
と urllib3
をインポートし、urllib3
からサブモジュール InsecureRequestWarning
をインポートします。 urllib3.disable_warnings
関数を使用して警告を無効にします。
requests.post()
ステートメントは try
ブロックの下に配置され、verify
フィールドは False
に設定されます。 これにより、期限切れのセキュリティ証明書のセキュリティ チェックが無効になります。
except
ブロック内では、エラー メッセージとともに SSLError
が発生します。
import requests
from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
try:
requests.post(
url="https://expired-rsa-dv.ssl.com/", data={"bar": "baz"}, verify=False
)
print("Connection made successfully")
except requests.exceptions.SSLError:
print("Expired Certificate")
出力:
Connection made successfully
まとめ
この記事では、Python で requests
を使用してセキュリティ証明書のチェックを無効にするさまざまな方法について説明します。 読者は、この記事を通じて、セキュリティ チェックを簡単に無効にすることができます。