Reputation: 730
In my twisted app I want to make an asynchronous request to Akismet to check for spam. Akismet reasonably uses HTTPS, so I've been following the web client guide on SSL in the docs. But there's this part that worries me:
Here’s an example which shows how to use Agent to request an HTTPS URL with no certificate verification.
I very much want certificate verification to prevent Man-In-The-Middle attacks. So how do I add it?
My test code without verification is this:
from twisted.internet import reactor
from twisted.web.client import Agent
from twisted.internet.ssl import ClientContextFactory
class WebClientContextFactory(ClientContextFactory):
def getContext(self, hostname, port):
print( "getting context for {}:{}".format( hostname, port ) )
# FIXME: no attempt to verify certificates!
return ClientContextFactory.getContext(self)
agent = Agent( reactor, WebClientContextFactory() )
def success( response ):
print( "connected!" )
def failure( failure ):
print( "failure: {}".format( failure ) )
def stop( ignored ):
reactor.stop()
agent.request( "GET", "https://www.pcwebshop.co.uk/" )\ # uses self-signed cert
.addCallbacks( success, failure )\
.addBoth( stop )
reactor.run()
I'd like it to fail due to inability to verify the cert.
Upvotes: 1
Views: 2325
Reputation: 31910
Thanks for pointing this out. This seems to be a bug in the documentation. Prior to version 14.0, it was accurate; Twisted would not validate HTTPS, and that was a big problem. However, as you can see in the release notes for that version, Twisted (at least in versions 14.0 and greater) does validate TLS on HTTPS connections made with Agent
. (It still does not do so for getPage
, the old, bad, HTTP client; do not use getPage
.)
I have filed this bug to track fixing the documentation to be accurate.
Upvotes: 2
Reputation: 16790
I'm using Twisted 15.1.0.
Actually, the default init function of Agent
will pass in BrowserLikePolicyForHTTPS
as contextFactory and have the ablility to verify server certificate.
Simply using this:
agent = Agent( reactor )
will produce the following error:
failure: [Failure instance: Traceback (failure with no frames):
<class 'twisted.web._newclient.ResponseNeverReceived'>:
[<twisted.python.failure.Failure <class 'OpenSSL.SSL.Error'>>]]
Make sure you installed service_identity
package using pip.
If you need custom cert verification, you can create a custom policy by passing the pem in, as described here:
customPolicy = BrowserLikePolicyForHTTPS(
Certificate.loadPEM(FilePath("your-trust-root.pem").getContent())
)
agent = Agent(reactor, customPolicy)
Upvotes: 5