見出し画像

Specify the encryption method and TLS in python3 to resolve "SSLEOFError"

この記事は、以下を英語化したものです。
This article is an English version of the following:

この記事のアクセス数が多く、皆さん困っている様なので英語化してみました。グーグル翻訳で訳しただけですが(笑)
This article has been accessed a lot and everyone seems to be having trouble, so I translated it into English.
However, I just translated it with Google Translate (lol)
-----------------------------------------------------------


When coding in python, I needed to specify the TLS version and encryption method at the same time, and I got hooked.
I'll also leave this as a memo so I don't forget.

Python 3.6.8 is used.
It's a bit old (lol)

Cause

When connecting to a certain server via https, there was a symptom where an "SSLEOFError" occurred.
This problem also seems to occur when the SSL communication settings allowed by the destination server and the SSL communication settings used by the connecting client (the client that causes the error) do not match.

The case I heard was about running python in an emulation environment on a Mac.
The case was, ``Even though I hadn't made any changes to the environment, one day an 'SSLEOFError' suddenly appeared and I was unable to connect.''

My guess is that an automatic update was performed on the OS side. I guess that's why it was updated to a new TLS version and encryption method.

If the server side is not compatible with the latest version, SSL communication cannot be continued. So the client side will get "SSLEOFError".

This time, I looked for a way to specify the TLS version and encryption method on the client side to solve this problem.

Basic code

The connection method used is urllib3, and the basic code is below.
This code simply accesses the set URL and retrieves the contents.

# -*- coding: utf-8 -*-
import urllib3

# Function: Get home page data.
# Notes: Connect to the destination specified by 'str_url' and get the response data.

# specify page
str_url = 'https://[destination url]/'

# connect to specified url
http = urllib3.PoolManager()
req = http.request('GET', str_url)


First, try only specifying the TLS version

When I looked into the technical information, I was able to specify a specific version by changing the part that creates the object to connect to the specified URL.

Change before:
http = urllib3.PoolManager()

After change:
http = urllib3.PoolManager(ssl_version=ssl.PROTOCOL_TLSv1_2)

In this example, TLS1.2 is specified.

The TLS version notation is as follows.
TLS1.0: ssl.PROTOCOL_TLSv1
TLS1.1: ssl.PROTOCOL_TLSv1_1
TLS1.2: ssl.PROTOCOL_TLSv1_2
TLS1.3: ssl.PROTOCOL_TLSv1_3

Specifying the encryption method

Next is to specify the encryption method.
I had a difficult time here.
I keep getting errors like there is no DEFAULT_CIPHERS attribute.

Finally, I asked ChatGPT again.
I rely on ChatGPT when I have a problem (lol)

Specifying the TLS version alone did not work, so another method was needed.
The answers from ChatGPT also had twists and turns,
I finally settled on the following code.

# -*- coding: utf-8 -*-
import urllib3
import ssl

# Function: Get home page data.
# Notes: Connect to the destination specified by 'str_url' and get the response data.

# specify page
str_url = 'https://[destination url]/'

# create custom SSL context
ssl_context = ssl.create_default_context()

# Specify the encryption method used on the socket
ssl_context.set_ciphers('RSA+AES')

# Specify TLS version
ssl_context.protocol = ssl.PROTOCOL_TLSv1_2


# Create a PoolManager for urllib3 and pass the custom SSL context.
http = urllib3.PoolManager(ssl_context=ssl_context)
req = http.request('GET', str_url)


Explanation of changes

  1. First, import the ssl library.
    import ssl

  2. Then create a custom SSL context.
    ssl_context = ssl.create_default_context()

  3. Specify the encryption method used on the socket in the created custom ssl context.
    ssl_context.set_ciphers('RSA+AES')

    1. You can see a sample of the format of the encryption method by looking at the following part of ssl_.py.
      DEFAULT_CIPHERS = ':'.join([
      'TLS13-AES-256-GCM-SHA384',
      'TLS13-CHACHA20-POLY1305-SHA256',
      'TLS13-AES-128-GCM-SHA256',
      'ECDH+AESGCM',
      'ECDH+CHACHA20',
      'DH+AESGCM',
      'DH+CHACHA20',
      'ECDH+AES256',
      'DH+AES256',
      'ECDH+AES128',
      'DH+AES',
      'RSA+AESGCM',
      'RSA+AES',
      '!aNULL',
      '!eNULL',
      '!MD5',
      ])

  4. Specify the TLS version.
    ssl_context.protocol = ssl.PROTOCOL_TLSv1_2

    1. For some reason, the cipher setting method [object].set_ciphers('str_sample')
      The format is completely different.
      ? ? ? ?
      However, after researching, this seems to be fine.

  5. Pass the custom SSL context when creating the PoolManager for urllib3.
    http = urllib3.PoolManager(ssl_context=ssl_context)


Now you can specify the TLS version and encryption method (ciphers) at the same time.

Lastly

If you connect to https and get "SSLEOFError", you may be able to resolve it by specifying a specific TLS version and ciphers.
I hope for your reference.

There seem to be various other patterns in which "SSLEOFerror" occurs. To find a solution, don't just assume this is the case, try searching and researching various things.

I think the key to solving this problem lies in asking yourself, "Why is SSL communication suddenly interrupted?" and finding the cause.


この記事が気に入ったらサポートをしてみませんか?