如何禁用pickle.loads以确保安全性?

时间:2018-04-30 23:14:41

标签: python pickle

出于安全考虑,我想在Python进程中禁用pickle.loads。我想继续使用pickle.dumps

有没有标准的方法来实现这一目标?

要明确我并不担心我的用户是恶意的。但是我担心他们可能会无意中使用以意外方式触发pickle.loads的库代码。

2 个答案:

答案 0 :(得分:0)

我不了解标准方法,但根据您的使用情况,我想到的一个想法是覆盖该功能:

pickle.loads = '_disabled'

答案 1 :(得分:0)

我认为像pickle.loads = disabled那样修补disabled引发一些异常是最容易的。如果您真的担心在有机会清除它之前缓存该函数,可以使用以下内容直接修补函数指针:

#include <Python.h>
#include <methodobject.h>

/**
   Patch the c implementation of a `builtin_function_or_method`.

   @param ob The builtin_function_or_method object to patch.
   @param new_meth The new C function pointer to use.
   @param new_flags The new flags to set.
   @param old_meth pointer to store the old function pointer in. If this
          function fails, this value will be unchanged. If this value is `NULL`,
          it will not be stored.
   @param old_meth pointer to store the old function pointer in. If this
          function fails, this value will be unchanged.
   @param old_flags A pointer to store the old flags in. If this function fails,
          this value will be unchanged. If this value is `NULL`, it will not be
          stored.
   @return zero if the method was patched succesfully, non-zero on failure. If
           this function returns non-zero, an exception will be raised.
*/
static int patch_c_function(PyObject* ob,
                            PyCFunction new_meth,
                            int new_flags,
                            PyCFunction* old_meth,
                            int* old_flags) {
    if (!PyCFunction_Check(ob)) {
        PyErr_Format(PyExc_TypeError,
                     "expected builtin_function_or_method object, got: %s",
                     Py_TYPE(ob)->tp_name);
        return -1;
    }

    PyCFunctionObject* function_object = (PyCFunctionObject*) ob;

    if (old_meth) {
        *old_meth = function_object->m_ml->ml_meth;
    }
    function_object->m_ml->ml_meth = new_meth;

    if (old_flags) {
        *old_flags = function_object->m_ml->ml_flags;
    }
    function_object->m_ml->ml_flags = new_flags;
    return 0;

}

static PyObject* disabled(void) {
    PyErr_SetString(PyExc_AssertionError,
                    "this function is disabled in this process");
    return NULL;
}

static PyObject* disable_function(PyObject* self, PyObject* f) {
    if (patch_c_function(f,
                         (PyCFunction) disabled,
                         METH_VARARGS | METH_KEYWORDS,
                         NULL,
                         NULL)) {
        return NULL;
    }
    Py_RETURN_NONE;
}

PyMethodDef methods[] = {
    {"disable_function", (PyCFunction) disable_function, METH_O, NULL},
    {NULL},
};

PyModuleDef cext_module = {
    PyModuleDef_HEAD_INIT,
    "cext",
    NULL,
    -1,
    methods,
    NULL,
    NULL,
    NULL,
    NULL
};


PyMODINIT_FUNC
PyInit_cext(void) {
    return PyModule_Create(&cext_module);
}

然后可以在以下的代码中使用:

In [1]: import pickle

In [2]: loads = pickle.loads

In [3]: from cext import disable_function

In [4]: disable_function(pickle.loads)

In [5]: pickle.loads()
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-5-95a055f9ba4f> in <module>()
----> 1 pickle.loads()

AssertionError: this function is disabled in this process

In [6]: loads()
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-6-73007b0e1946> in <module>()
----> 1 loads()

AssertionError: this function is disabled in this process