I’m often writing Python code that talks to ReST APIs, and an important element of the transfer code is security. You don’t want to accidentally expose credentials, user data, or any of the other sensitive information in the API calls to unintended or malicious audiences.
Security in API transfers is so important, in fact, that I generally don’t write it myself.
I’m usually using the popular
requests Python library for my transfers, and it uses
certifi for Certificate Authority trust, it uses the SSL capabilities that the Python
interpreter was compiled with (often OpenSSL in my case), and just generally handles tons
of low-level stuff that I do not intend to trust myself to handle.
However, occasionally, I have a problem: I need to talk to some site with a less-than-perfect TLS configuration. Maybe their certificate is expired; maybe the certificate itself is valid but they’re not properly appending the intermediate certificates; maybe their TLS libraries are so old that we can’t complete a handshake without me turning some settings down on my end. In all of these cases, the ideal solution is to fix the site’s TLS config.
However, sometimes that’s not an option, or at least not immediately, and you still need to write some
Python to talk to the API. In those cases,
requests and friends will dump all sorts of lovely
warnings into your terminal about how what you’re doing is a bad idea. You’ll want to disable
those warnings, and a quick search online might suggest doing the following:
import requests requests.packages.urllib3.disable_warnings()
BUT DON’T DO THAT!
That configuration will work, but it will disable all urllib3 warnings, globally. This means that if your code talks to 10 different sites but only one of them is misconfigured, it will now ignore any and all TLS warnings, not just the ones that are causing you trouble. Instead, I offer this simple function:
import warnings def ignore_for_host(host: str, exception: type) -> None: warnings.filterwarnings( "ignore", message=".*" + host, category=exception )
You can call this with the offending site and the specific type of exception you want to ignore, thus leaving all other warnings enabled:
from requests.packages.urllib3 import exceptions ignore_for_host("sslv3.example.com", exceptions.InsecureRequestWarning)
This example will ignore
InsecureRequestWarnings for sslv3.example.com only. Remember, both the
client and the server in any API transfer should maintain current TLS configs so that no warnings
are generated to begin with. If something changes and new warnings are being generated, you want
to know about it, so it’s best to write your code to only ignore the specific warnings that you’re
forced to live with for now.