I'm using python 2.7 and I'd like to get the contents of a webpage that requires sslv3. Currently when I try to access the page I get the error SSL23_GET_SERVER_HELLO, and some searching on the web lead me to the following solution which fixes things in Python 3
urllib.request.install_opener(urllib.request.build_opener(urllib.request.HTTPSHandler(context=ssl.SSLContext(ssl.PROTOCOL_TLSv1))))
How can I get the same effect in python 2.7, as I can't seem to find the equivalent of the context argument for the HTTPSHandler class.
I realize this response is a few years too late, but I also ran into the same problem, and didn't want to depend on libcurl being installed on a machine where I ran this. Hopefully, this will be useful to those who find this post in the future.
The problem is that httplib.HTTPSConnection.connect doesn't have a way to specify SSL context or version. You can overwrite this function before you hit the meat of your script for a quick solution.
An important consideration is that this workaround, as discussed above, will not verify the validity of the server's certificate.
import httplib
import socket
import ssl
import urllib2
def connect(self):
"Connect to a host on a given (SSL) port."
sock = socket.create_connection((self.host, self.port),
self.timeout, self.source_address)
if self._tunnel_host:
self.sock = sock
self._tunnel()
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_TLSv1)
httplib.HTTPSConnection.connect = connect
opener = urllib2.build_opener()
f = opener.open('https://www.google.com/')
*Note: this alternate connect() function was copy/pasted from httplib.py, and simply modified to specify the ssl_version in the wrap_socket() call
SSL should be handled automatically as long as you have the SSL libraries installed on your server (i.e. you shouldn't have to specificially add it as a handler)
http://docs.python.org/library/urllib2.html#urllib2.build_opener
If the Python installation has SSL support (i.e., if the ssl module can be imported), HTTPSHandler will also be added.
Also, note that urllib and urllib2 have been merged in python 3 so their approach is a little different
Since I was unable to do this using urllib2, I eventually gave in and moved to using the libCurl bindings like #Bruno had suggested in the comments to pastylegs answer.
Related
I am trying to connect to Gmail's SMTP using sockets in Python3. With this code (omitting the response-recieving parts):
import ssl
import base64
from socket import *
cs = socket(AF_INET, SOCK_STREAM)
cs.connect(("smtp.gmail.com", 587))
cs.send(b'EHLO smtp.google.com\r\n')
cs.send(b'STARTTLS\r\n')
ws = ssl.wrap_socket(cs, ssl_version=ssl.PROTOCOL_TLSv1, ciphers="ADH-AES256-SHA")
But I'm getting the following error in do_handshake
in the last line:
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:645)
I have also tried the following version in the last line:
ssl_version=ssl.PROTOCOL_SSLv23
ssl.PROTOCOL_TLSv1
ssl.OP_NO_SSLv3
ssl.OP_NO_TLSv1
ssl.PROTOCOL_SSLv2
ssl.PROTOCOL_SSLv23
ssl.PROTOCOL_SSLv3
ssl.PROTOCOL_TLSv1
Am I doing something wrong ? Thanks.
The problem is that you're never receiving on your socket. You may be able to get away with that on some servers (have my doubts) but Google's servers don't like it. Really don't think it would work with any server as I'm pretty sure you need a clean receive buffer so the TLS negotiation can take place without a bunch of prior junk still in the pipeline.
Your code is working with the following changes for me:
import ssl
import base64
from socket import *
cs = socket(AF_INET, SOCK_STREAM)
cs.connect(("smtp.gmail.com", 587))
print(cs.recv(4096))
cs.send(b'EHLO smtp.google.com\r\n')
print(cs.recv(4096))
cs.send(b'STARTTLS\r\n')
print(cs.recv(4096))
ws = ssl.wrap_socket(cs, ssl_version=ssl.PROTOCOL_TLSv1)
ws.send(b'MAIL FROM: abc#def.com\r\n')
print(ws.recv(4096))
But as has already been mentioned in the comments, unless this is just for fun and/or a learning experience, you should be using python's smtplib.
I'm following the tutorial To Russia With Love, and as part of this I want to change the identity everytime I run the code. I've looked at multiple questions and tutorials and from the looks of it my torrc-defaults file is correct as it has:
ControlPort 9151
CookieAuthentication 1
I wanted to edit the torrc file first but if i touch it Tor won't run anymore, so i read somewhere to look at torrc instead. The torrc file alone only has:
# This file was generated by Tor; if you edit it, comments will not be preserved
# The old torrc file was renamed to torrc.orig.1 or similar, and Tor will ignore it
I don't want to set a password so my understanding from reading the stem documents is that setting the Authentication is enough. I have the following code:
import socks # SocksiPy module
import socket
import requests
SOCKS_PORT = 9150
# Set socks proxy and wrap the urllib module
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, '127.0.0.1', SOCKS_PORT)
socket.socket = socks.socksocket
def getaddrinfo(*args):
return [(socket.AF_INET, socket.SOCK_STREAM, 6, '', (args[0], args[1]))]
socket.getaddrinfo = getaddrinfo
url = "http://google.com"
print requests.get(url).elapsed.total_seconds()
from stem import Signal
from stem.control import Controller
with Controller.from_port(port = 9151) as controller:
controller.authenticate()
controller.signal(Signal.NEWNYM)
But when I run it i get the error:
socks.SOCKS5Error: 0x01: General SOCKS server failure
I'm not sure what to do, i've been reading about this for hours and haven't been able to solve the problem. Any hints would be great.
EDIT:
I've also read through This Post, but it doesn't seem like there's a solution.
I also tried putting the Controller statement before setting the sockets, but in that case the IP remains the same and doesn't change.
I ended up solving this problem by moving the controller statement before setting the sockets. Initially it looked like the IP remains the same but turns out if you wait an extra 3 or 4 seconds the IP changes, so I just added a time delay and it runs fine.
I'm using Python 2.4.4 and OpenSSL 0.9.8k (not by choice)
I've referred to the documentation: https://docs.python.org/release/2.4.4/lib/module-socket.html
and to pretty much every mention of "openSSL" and "python" on the internet, and I haven't found a solution to my problem.
I'm simply writing a test program to initiate an SSL connection. Here is the code:
server
#!/usr/bin/python
import socket
import _ssl
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 4433))
s.listen(5)
while True:
client, address = s.accept()
ssl_client = socket.ssl(client,
keyfile='keyfile',
certfile='certfile')
print "Connection: ", address
data = ssl_client.read(1024)
if data:
print "received data: ", data
ssl_client.write(data + " Hello, World!")
del ssl_client
client.close()
client
#!/usr/bin/python
import socket
import _ssl
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('host', 4433))
ssl_s = socket.ssl(s,
keyfile='keyfile',
certfile='certfile')
print 'writing ', ssl_s.write("Hello, World!"), ' bytes to ssl stream'
data = ssl_s.read(1024)
del ssl_s
s.close()
print "received data: ", data
Some notes about this code - keyfile and certfile are paths to my actual key and cert file. Those arguments are not the issue. The hostnames are also not the issue. I'm aware that the port used is 4433 - in our requirements, we're meant to use a generic port, not 443. I was unaware that it was possible to use SSL over a different port, but regardless, even when I use 443 I get the exact same error.
I can run the server fine, and then when I run the client, I get the following error on the wrap_socket lines for both client and server:
error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol
I've read it's due to using a non-443 port, but again, using 443 didn't fix things. I've read it could be a protocol mismatch, but the client and the server are both defaulting to SSL2.3. We're meant to use TLS1.2 as per our requirements, but the docs don't seem to have any information on how to set the SSL protocol version. I'm unsure if that's related to my issue. Please keep in mind I'm not here to open a dialogue regarding to use of outdated SSL and Python versions.
socket.ssl is only able to initiate a SSL connection and the given optional cert and key are for use of client certificates. socket.ssl is not able to be used on the server side and it looks like python 2.4.4 does not offer this feature in any of the core modules at all. In later versions of python you can use the ssl module for this but 2.4.4 does not seem to have this.
I am writing a crawler in Python that will run through Tor. I have Tor working and used code from this YouTube tutorial on how to route my Python requests to go through the Tor SOCKS proxy at 127.0.0.1:9050.
What I can't figure out is how to toggle this on/off within my script. Some requests I want to go through Tor and some I don't. Basically, I can't figure out the correct "close" or "shutdown" method in the socket objects I am using because I don't understand them.
Here's what happens now
import socket
import socks
import requests
def connect_to_socks():
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, '127.0.0.1', 9050, True)
socket.socket = socks.socksocket
r = requests.get('http://wtfismyip.com/text')
print r.text #prints my ordinary IP address
connect_to_socks()
r = requests.get('http://wtfismyip.com/text')
print r.text #prints my Tor IP address
How do I turn off the socket routing to the SOCKS proxy so that it goes through my ordinary internet connection?
I'm hoping to use requests instead of urllib2 as it seems a lot easier but if I have to get into the guts of urllib2 or even httplib I will. But would prefer not to.
Figured it out by listening to this good YouTube tutorial.
Just need to call socket.setdefaultproxy() and it brings me back.
For Python 3 you can set back default socket by using this:
socks.setdefaultproxy(None)
socket.socket = socks.socksocket
I write this python code:
import socks
import socket
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, "64.83.219.7", 58279)
socket.socket = socks.socksocket
socket.setdefaulttimeout(19)
import urllib2
print urllib2.urlopen('http://www.google.com').read()
but when I execute it, I get this error:
urllib2.URLError: <urlopen error timed out>
What am I doing wrong?
Something timed out in your script. I guess the connection to google because of wrong proxy setup. I think your goal is to fetch the contents of http://www.google.com through a proxy?
I don't know about this method to set it using socket/socks module. Maybe you want to take a look at the following chapters in the python documentation:
http://docs.python.org/library/urllib2.html?highlight=urllib2#examples (code sinppet 5 and the text above)
http://docs.python.org/library/urllib2.html?highlight=urllib2#urllib2.Request.set_proxy
http://docs.python.org/library/urllib2.html?highlight=urllib2#proxyhandler-objects