-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
A hook for certificate verification overrides #5019
Comments
Instead of providing an additional hook, I think this is better solved by configuring from mitmproxy import tls
from mitmproxy.addons.tlsconfig import TlsConfig
class UserTlsConfig(TlsConfig):
def tls_start_server(self, tls_start: tls.TlsData):
super().tls_start_server(tls_start) # use the default implementation to setup the pyOpenSSL context
print(f"{tls_start.ssl_conn=}") # do modifications here, e.g. set VERIFY_NONE for some domains
addons = [UserTlsConfig()]
For the record, there are also the |
I was afraid that wouldn't work because I'll see if I can do anything with the store, as it seems to be better fit for what I want to do (i. e. trust specific certificates for some connections, and not just disable verification completely). |
Completely forgot that it will only help with self-signed certs, not expired ones. So the point about |
I fell into this today. I tried to override the EDIT: Here's my use case: https://stackoverflow.com/questions/70515761/trusting-individual-invalid-certs-in-mitmproxy |
See this: jsmucr@05118e5 import json, copy
from mitmproxy import ctx
def tls_start_server(data: any):
address = data.context.server.address[0] + ":" + str(data.context.server.address[1])
if address == 'as2.pipechain.com:10443':
data.context.options = copy.deepcopy(data.context.options)
data.context.options.ssl_insecure = True
ctx.log.info("ssl_insecure[" + address + "] => " + str(data.context.options.ssl_insecure)) Is this the correct way to go? Global context is IMO generally a bad thing. |
@jsmucr Ohh, can you create a PR with those changes? Thanks. |
Thank you for putting much more work into this @vthriller and @jsmucr! 🍰 @jsmucr's PR is great, but unfortunately doesn't fly for architectural reasons. Nonetheless, thank you very much! 🍰
This sounds like the most reasonable approach may just be to get Alternatively, here's the workaround implementation where SSL.Connection is just created again: from mitmproxy import tls
from mitmproxy.addons.tlsconfig import TlsConfig
from OpenSSL import SSL
class UserTlsConfig(TlsConfig):
def tls_start_server(self, tls_start: tls.TlsData):
super().tls_start_server(tls_start)
if tls_start.conn.sni == "wrong.host.badssl.com":
# Get existing SSL.Context context and disable verification
ssl_ctx = tls_start.ssl_conn.get_context()
ssl_ctx.set_verify(SSL.VERIFY_NONE, None)
# Build a new SSL.Connection object as the existing one has copied the old verification flags.
# (this code is adapted from the buitlin TlsConfig addon)
tls_start.ssl_conn = SSL.Connection(ssl_ctx)
tls_start.ssl_conn.set_tlsext_host_name(tls_start.conn.sni.encode())
tls_start.ssl_conn.set_connect_state()
addons = [UserTlsConfig()] |
@mhils I tried your workaround and it appears to work ok. Sadly -- only unless you do not plan to reconfigure the ssl_ctx.set_options(SSL.OP_NO_SSLv3) The effect of the line above is irreversible for a single host. I can't enable SSLv3 for that host again unless I restart mitmproxy. This whole thing is anything but my domain, so I may be missing something important. Any ideas? |
Surely that'd be the best solution, however relevant PR remains untouched for almost 3 years now, so I don't have much hopes in that regard.
Is there any reason to prefer
Um, wouldn't that bypass literal IP check performed in the |
The cryptography/pyOpenSSL folks are usually fantastic, this one may just have slipped through or they consider it out of scope. Let's see if we get a positive answer to pyca/pyopenssl#255 (comment). In either case, we have a relatively decent workaround anyways. If necessary we can move the context -> connection logic into a separate function that can be reused.
When dealing with non-malicious clients both are consistent. There are some edge cases where they differ:
Per the spec, Server Name Indication values must be DNS names and not IP addresses, so we don't want to set an IP as SNI. Many implementations don't care in practice, but some do refuse to serve traffic. I don't think it's ever a security issue, only a potential compatibility problem with some servers. In the example I posted we've already established that the SNI is |
Just an addition to my last post: As a workaround I have to clear the context generator cache if the SSL options change. net_tls.create_proxy_server_context.cache_clear() @vthriller Here's the current state of my solution if it helps: https://gist.github.com/jsmucr/24cf0859dd7c9bba8eb2817d7b0bf4b6 |
Quick update: We got the underlying bindings into cryptography (pyca/cryptography@b6e7b07) and I have prepared a PR for pyOpenSSL (pyca/pyopenssl#1073), which should be ready to merge once cryptography ships a new release. So this will take some time for upstream to move, but we'll eventually get |
Problem Description
It seems there is currently no way to tell mitmproxy to accept individual invalid server certificates¹,
--ssl-insecure
/--no-ssl-insecure
is as granular as it currently gets. This is a problem for people that use mitmproxy for casual browsing and occasionally stumble upon some non-critical websites (like, say, blogs) with annoyances like slightly outdated certs.¹ Or maybe even discard valid ones? I'm not sure if anyone would find such feature useful though, so I'll speak about verification overrides for the rest of this post.
Proposal
A hook that will let addons choose
Verify.VERIFY_NONE
orVerify.VERIFY_PEER
for each individual certificate and/or host.Alternatives
ssl_insecure
option so that it could also accept a list of filters of some sort.ssl_insecure
could accept path to file with a list of overrides.cert_override.txt
). (Can't say anything about WebKit/Blink-based browsers though.)Additional context
Gecko's
nsCertOverrideService.cpp
describes override matching process, as well as format ofcert_override.txt
, which basically boils down to:host:port
, SHA-256 fingerprint, error kinds (any combination ofM
ismatch,U
ntrusted,T
ime), and DB key, which itself is generated from serial and DN.The text was updated successfully, but these errors were encountered: