diff --git a/django/contrib/sessions/serializers.py b/django/contrib/sessions/serializers.py index f1adf91c22..16a248cc65 100644 --- a/django/contrib/sessions/serializers.py +++ b/django/contrib/sessions/serializers.py @@ -1,6 +1,3 @@ -# RemovedInDjango50Warning. -from django.core.serializers.base import PickleSerializer as BasePickleSerializer from django.core.signing import JSONSerializer as BaseJSONSerializer JSONSerializer = BaseJSONSerializer -PickleSerializer = BasePickleSerializer diff --git a/django/core/serializers/base.py b/django/core/serializers/base.py index 517d2cad85..20dffac05f 100644 --- a/django/core/serializers/base.py +++ b/django/core/serializers/base.py @@ -1,38 +1,14 @@ """ Module for abstract serializer/unserializer base classes. """ -import pickle -import warnings from io import StringIO from django.core.exceptions import ObjectDoesNotExist from django.db import models -from django.utils.deprecation import RemovedInDjango50Warning DEFER_FIELD = object() -class PickleSerializer: - """ - Simple wrapper around pickle to be used in signing.dumps()/loads() and - cache backends. - """ - - def __init__(self, protocol=None): - warnings.warn( - "PickleSerializer is deprecated due to its security risk. Use " - "JSONSerializer instead.", - RemovedInDjango50Warning, - ) - self.protocol = pickle.HIGHEST_PROTOCOL if protocol is None else protocol - - def dumps(self, obj): - return pickle.dumps(obj, self.protocol) - - def loads(self, data): - return pickle.loads(data) - - class SerializerDoesNotExist(KeyError): """The requested serializer was not found.""" diff --git a/docs/releases/5.0.txt b/docs/releases/5.0.txt index fb052b77f1..d39b8d314a 100644 --- a/docs/releases/5.0.txt +++ b/docs/releases/5.0.txt @@ -317,3 +317,5 @@ to remove usage of these features. * The undocumented ability to pass ``errors=None`` to ``SimpleTestCase.assertFormError()`` and ``assertFormsetError()`` is removed. + +* ``django.contrib.sessions.serializers.PickleSerializer`` is removed. diff --git a/docs/topics/http/sessions.txt b/docs/topics/http/sessions.txt index 4dc6f6af35..fd2f106739 100644 --- a/docs/topics/http/sessions.txt +++ b/docs/topics/http/sessions.txt @@ -122,20 +122,6 @@ and the :setting:`SECRET_KEY` setting. .. warning:: - **If the** ``SECRET_KEY`` **or** ``SECRET_KEY_FALLBACKS`` **are not kept - secret and you are using the** - ``django.contrib.sessions.serializers.PickleSerializer``, **this can lead - to arbitrary remote code execution.** - - An attacker in possession of the :setting:`SECRET_KEY` or - :setting:`SECRET_KEY_FALLBACKS` can not only generate falsified session - data, which your site will trust, but also remotely execute arbitrary code, - as the data is serialized using pickle. - - If you use cookie-based sessions, pay extra care that your secret key is - always kept completely secret, for any system which might be remotely - accessible. - **The session data is signed but not encrypted** When using the cookies backend the session data can be read by the client. @@ -373,17 +359,6 @@ Bundled serializers See the :ref:`custom-serializers` section for more details on limitations of JSON serialization. -.. class:: serializers.PickleSerializer - - Supports arbitrary Python objects, but, as described above, can lead to a - remote code execution vulnerability if :setting:`SECRET_KEY` or any key of - :setting:`SECRET_KEY_FALLBACKS` becomes known by an attacker. - - .. deprecated:: 4.1 - - Due to the risk of remote code execution, this serializer is deprecated - and will be removed in Django 5.0. - .. _custom-serializers: Write your own serializer diff --git a/tests/defer_regress/tests.py b/tests/defer_regress/tests.py index 9f94d5fac1..33193e187a 100644 --- a/tests/defer_regress/tests.py +++ b/tests/defer_regress/tests.py @@ -1,11 +1,9 @@ from operator import attrgetter from django.contrib.contenttypes.models import ContentType -from django.contrib.sessions.backends.db import SessionStore from django.db import models from django.db.models import Count -from django.test import TestCase, ignore_warnings, override_settings -from django.utils.deprecation import RemovedInDjango50Warning +from django.test import TestCase from .models import ( Base, @@ -106,29 +104,6 @@ class DeferRegressionTest(TestCase): list(SimpleItem.objects.annotate(Count("feature")).only("name")), list ) - @ignore_warnings(category=RemovedInDjango50Warning) - @override_settings( - SESSION_SERIALIZER="django.contrib.sessions.serializers.PickleSerializer" - ) - def test_ticket_12163(self): - # Test for #12163 - Pickling error saving session with unsaved model - # instances. - SESSION_KEY = "2b1189a188b44ad18c35e1baac6ceead" - - item = Item() - item._deferred = False - s = SessionStore(SESSION_KEY) - s.clear() - s["item"] = item - s.save(must_create=True) - - s = SessionStore(SESSION_KEY) - s.modified = True - s.save() - - i2 = s["item"] - self.assertFalse(i2._deferred) - def test_ticket_16409(self): # Regression for #16409 - make sure defer() and only() work with annotate() self.assertIsInstance( diff --git a/tests/serializers/tests.py b/tests/serializers/tests.py index 3cc937d58d..41997c98fb 100644 --- a/tests/serializers/tests.py +++ b/tests/serializers/tests.py @@ -1,4 +1,3 @@ -import pickle from datetime import datetime from functools import partialmethod from io import StringIO @@ -6,12 +5,11 @@ from unittest import mock, skipIf from django.core import serializers from django.core.serializers import SerializerDoesNotExist -from django.core.serializers.base import PickleSerializer, ProgressBar +from django.core.serializers.base import ProgressBar from django.db import connection, transaction from django.http import HttpResponse from django.test import SimpleTestCase, override_settings, skipUnlessDBFeature -from django.test.utils import Approximate, ignore_warnings -from django.utils.deprecation import RemovedInDjango50Warning +from django.test.utils import Approximate from .models import ( Actor, @@ -487,31 +485,6 @@ class SerializersTransactionTestBase: self.assertEqual(art_obj.author.name, "Agnes") -class PickleSerializerTests(SimpleTestCase): - @ignore_warnings(category=RemovedInDjango50Warning) - def test_serializer_protocol(self): - serializer = PickleSerializer(protocol=3) - self.assertEqual(serializer.protocol, 3) - # If protocol is not provided, it defaults to pickle.HIGHEST_PROTOCOL - serializer = PickleSerializer() - self.assertEqual(serializer.protocol, pickle.HIGHEST_PROTOCOL) - - @ignore_warnings(category=RemovedInDjango50Warning) - def test_serializer_loads_dumps(self): - serializer = PickleSerializer() - test_data = "test data" - dump = serializer.dumps(test_data) - self.assertEqual(serializer.loads(dump), test_data) - - def test_serializer_warning(self): - msg = ( - "PickleSerializer is deprecated due to its security risk. Use " - "JSONSerializer instead." - ) - with self.assertRaisesMessage(RemovedInDjango50Warning, msg): - PickleSerializer() - - def register_tests(test_class, method_name, test_func, exclude=()): """ Dynamically create serializer tests to ensure that all registered