luc
luc

Reputation: 43096

Why do I get a "SSL error: called a function you should not call" with Django

I have a Python 3.5/Django 1.10 app served by Apache/mod_wsgi over SSL. It is connected to a Postgres 9.5.2 database (with psycopg2==2.6.2) and is running on a server at AlwaysData

It works fine most of time but I have sometimes an error that I don't understand.

(SSL error: called a function you should not call)

If I put the following database settings : The error seems to happen every time

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'db',
        'USER': 'user',
        'PASSWORD': 'password',
        'HOST': 'host',
        'PORT': '',
        'OPTIONS': {
            'sslmode': 'require',
        },
    }
}

It seems to occur while querying the database.

# django/db/backends/utils.py line 64
return self.cursor.execute(sql, params)

The problem occurs when REST api (made using django-rest-framework) is called by a Angular2 app.

I have activated the following settings:

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

Why does it happen? How to fix this problem in my Django project.

Note : This question looks similar but I don't manage the OpenSSL layer directly so it is not very helpful.

EDIT : here is the full traceback

File "proj/env/lib/python3.5/site-packages/django/core/handlers/exception.py" in inner
  39.             response = get_response(request)

File "proj/env/lib/python3.5/site-packages/django/core/handlers/base.py" in _legacy_get_response
  249.             response = self._get_response(request)

File "proj/env/lib/python3.5/site-packages/django/core/handlers/base.py" in _get_response
  187.                 response = self.process_exception_by_middleware(e, request)

File "proj/env/lib/python3.5/site-packages/django/core/handlers/base.py" in _get_response
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "proj/env/lib/python3.5/site-packages/django/views/decorators/csrf.py" in wrapped_view
  58.         return view_func(*args, **kwargs)

File "proj/env/lib/python3.5/site-packages/django/views/generic/base.py" in view
  68.             return self.dispatch(request, *args, **kwargs)

File "proj/env/lib/python3.5/site-packages/rest_framework/views.py" in dispatch
  474.             response = self.handle_exception(exc)

File "proj/env/lib/python3.5/site-packages/rest_framework/views.py" in handle_exception
  434.             self.raise_uncaught_exception(exc)

File "proj/env/lib/python3.5/site-packages/rest_framework/views.py" in dispatch
  471.             response = handler(request, *args, **kwargs)

File "proj/apps/costs/apis.py" in get
  296.         data = self.get_spends_stats(cost_items, perimeter, start_date, end_date)

File "proj/apps/costs/apis.py" in get_spends_stats
  306.         for building in buildings:

File "proj/env/lib/python3.5/site-packages/django/db/models/query.py" in __iter__
  256.         self._fetch_all()

File "proj/env/lib/python3.5/site-packages/django/db/models/query.py" in _fetch_all
  1087.             self._result_cache = list(self.iterator())

File "proj/env/lib/python3.5/site-packages/django/db/models/query.py" in __iter__
  54.         results = compiler.execute_sql()

File "proj/env/lib/python3.5/site-packages/django/db/models/sql/compiler.py" in execute_sql
  835.             cursor.execute(sql, params)

File "proj/env/lib/python3.5/site-packages/django/db/backends/utils.py" in execute
  64.                 return self.cursor.execute(sql, params)

File "proj/env/lib/python3.5/site-packages/django/db/utils.py" in __exit__
  94.                 six.reraise(dj_exc_type, dj_exc_value, traceback)

File "proj/env/lib/python3.5/site-packages/django/utils/six.py" in reraise
  685.             raise value.with_traceback(tb)

File "proj/env/lib/python3.5/site-packages/django/db/backends/utils.py" in execute
  64.                 return self.cursor.execute(sql, params)

Exception Type: OperationalError at /costs/api/benchmark/cost-center/3/38/2016-01/2017-12/
Exception Value: SSL error: called a function you should not call

Upvotes: 1

Views: 1632

Answers (3)

hynekcer
hynekcer

Reputation: 15548

There was a related bug #58956 in Apache + OpenSSL in SSL_shutdown handshake, ending with exactly the same error message, that has been fixed by OpenSSL in February 2016. Try to upgrade to 1.0.2g or 1.1.0 or newer.


EDIT: If you have some 1.0.2 version (maybe more versions, but your package of interest is linked to 1.0.2) then the upgrade of SSL is worth considering. The version 1.1.0 is here written only for completeness to anybody can easily check a version later, whether is related to this bug. Nobody have now a 1.1 probably on a production hosting and a self-made upgrade to it would be probably a bad idea.

Upvotes: 1

luc
luc

Reputation: 43096

The problem seems to be solved by changing the database settings

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'name',
        'USER': 'user',
        'PASSWORD': 'password',
        'HOST': 'host',
        'PORT': '',
        'OPTIONS': {
            'sslmode': 'disable',
        },
    }
}

If not set the option is using prefer as default (see https://www.postgresql.org/docs/9.5/static/libpq-ssl.html) which seems to have unpredicted behavior.

I guess that the root cause is an OpenSSL mismatch between Apache and Postgres. It has to be investigated.

The current fix makes the database connection not secured but this is another story.

Upvotes: 0

ivan_pozdeev
ivan_pozdeev

Reputation: 35986

Looks like a psycopg2 bug (or rather, as piro pointed out, the underlying libpq's bug). It appears to be violating the required call order - likely not waiting for some event. Since this occurs irregularly, it can be a race condition.

It even provides incomplete information about the error which is another bug. It should use ERR_print_errors() to get the full message which has the format [pid]:error:[error code]:[library name]:[function name]:[reason string]:[file name]:[line]:[optional text message].

Upvotes: 1

Related Questions