1
# -*- coding: utf-8 -*-
6
Adds a sandbox layer to Jinja as it was the default behavior in the old
7
Jinja 1 releases. This sandbox is slightly different from Jinja 1 as the
8
default behavior is easier to use.
10
The behavior can be changed by subclassing the environment.
12
:copyright: (c) 2010 by the Jinja Team.
16
from jinja2.environment import Environment
17
from jinja2.exceptions import SecurityError
18
from jinja2._compat import string_types, function_type, method_type, \
19
traceback_type, code_type, frame_type, generator_type, PY2
22
#: maximum number of items a range may produce
25
#: attributes of function objects that are considered unsafe.
26
UNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict',
27
'func_defaults', 'func_globals'])
29
#: unsafe method attributes. function attributes are unsafe for methods too
30
UNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self'])
32
#: unsafe generator attirbutes.
33
UNSAFE_GENERATOR_ATTRIBUTES = set(['gi_frame', 'gi_code'])
35
# On versions > python 2 the special attributes on functions are gone,
36
# but they remain on methods and generators for whatever reason.
38
UNSAFE_FUNCTION_ATTRIBUTES = set()
42
# make sure we don't warn in python 2.6 about stuff we don't care about
43
warnings.filterwarnings('ignore', 'the sets module', DeprecationWarning,
44
module='jinja2.sandbox')
46
from collections import deque
48
_mutable_set_types = (set,)
49
_mutable_mapping_types = (dict,)
50
_mutable_sequence_types = (list,)
53
# on python 2.x we can register the user collection types
55
from UserDict import UserDict, DictMixin
56
from UserList import UserList
57
_mutable_mapping_types += (UserDict, DictMixin)
58
_mutable_set_types += (UserList,)
62
# if sets is still available, register the mutable set from there as well
65
_mutable_set_types += (Set,)
69
#: register Python 2.6 abstract base classes
71
from collections import MutableSet, MutableMapping, MutableSequence
72
_mutable_set_types += (MutableSet,)
73
_mutable_mapping_types += (MutableMapping,)
74
_mutable_sequence_types += (MutableSequence,)
79
(_mutable_set_types, frozenset([
80
'add', 'clear', 'difference_update', 'discard', 'pop', 'remove',
81
'symmetric_difference_update', 'update'
83
(_mutable_mapping_types, frozenset([
84
'clear', 'pop', 'popitem', 'setdefault', 'update'
86
(_mutable_sequence_types, frozenset([
87
'append', 'reverse', 'insert', 'sort', 'extend', 'remove'
90
'append', 'appendleft', 'clear', 'extend', 'extendleft', 'pop',
91
'popleft', 'remove', 'rotate'
96
def safe_range(*args):
97
"""A range that can't generate ranges with a length of more than
101
if len(rng) > MAX_RANGE:
102
raise OverflowError('range too big, maximum size for range is %d' %
108
"""Marks a function or method as unsafe.
116
f.unsafe_callable = True
120
def is_internal_attribute(obj, attr):
121
"""Test if the attribute given is an internal python attribute. For
122
example this function returns `True` for the `func_code` attribute of
123
python objects. This is useful if the environment method
124
:meth:`~SandboxedEnvironment.is_safe_attribute` is overridden.
126
>>> from jinja2.sandbox import is_internal_attribute
127
>>> is_internal_attribute(lambda: None, "func_code")
129
>>> is_internal_attribute((lambda x:x).func_code, 'co_code')
131
>>> is_internal_attribute(str, "upper")
134
if isinstance(obj, function_type):
135
if attr in UNSAFE_FUNCTION_ATTRIBUTES:
137
elif isinstance(obj, method_type):
138
if attr in UNSAFE_FUNCTION_ATTRIBUTES or \
139
attr in UNSAFE_METHOD_ATTRIBUTES:
141
elif isinstance(obj, type):
144
elif isinstance(obj, (code_type, traceback_type, frame_type)):
146
elif isinstance(obj, generator_type):
147
if attr in UNSAFE_GENERATOR_ATTRIBUTES:
149
return attr.startswith('__')
152
def modifies_known_mutable(obj, attr):
153
"""This function checks if an attribute on a builtin mutable object
154
(list, dict, set or deque) would modify it if called. It also supports
155
the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and
156
with Python 2.6 onwards the abstract base classes `MutableSet`,
157
`MutableMapping`, and `MutableSequence`.
159
>>> modifies_known_mutable({}, "clear")
161
>>> modifies_known_mutable({}, "keys")
163
>>> modifies_known_mutable([], "append")
165
>>> modifies_known_mutable([], "index")
168
If called with an unsupported object (such as unicode) `False` is
171
>>> modifies_known_mutable("foo", "upper")
174
for typespec, unsafe in _mutable_spec:
175
if isinstance(obj, typespec):
176
return attr in unsafe
180
class SandboxedEnvironment(Environment):
181
"""The sandboxed environment. It works like the regular environment but
182
tells the compiler to generate sandboxed code. Additionally subclasses of
183
this environment may override the methods that tell the runtime what
184
attributes or functions are safe to access.
186
If the template tries to access insecure code a :exc:`SecurityError` is
187
raised. However also other exceptions may occour during the rendering so
188
the caller has to ensure that all exceptions are catched.
192
#: default callback table for the binary operators. A copy of this is
193
#: available on each instance of a sandboxed environment as
194
#: :attr:`binop_table`
195
default_binop_table = {
199
'/': operator.truediv,
200
'//': operator.floordiv,
205
#: default callback table for the unary operators. A copy of this is
206
#: available on each instance of a sandboxed environment as
207
#: :attr:`unop_table`
208
default_unop_table = {
213
#: a set of binary operators that should be intercepted. Each operator
214
#: that is added to this set (empty by default) is delegated to the
215
#: :meth:`call_binop` method that will perform the operator. The default
216
#: operator callback is specified by :attr:`binop_table`.
218
#: The following binary operators are interceptable:
219
#: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**``
221
#: The default operation form the operator table corresponds to the
222
#: builtin function. Intercepted calls are always slower than the native
223
#: operator call, so make sure only to intercept the ones you are
226
#: .. versionadded:: 2.6
227
intercepted_binops = frozenset()
229
#: a set of unary operators that should be intercepted. Each operator
230
#: that is added to this set (empty by default) is delegated to the
231
#: :meth:`call_unop` method that will perform the operator. The default
232
#: operator callback is specified by :attr:`unop_table`.
234
#: The following unary operators are interceptable: ``+``, ``-``
236
#: The default operation form the operator table corresponds to the
237
#: builtin function. Intercepted calls are always slower than the native
238
#: operator call, so make sure only to intercept the ones you are
241
#: .. versionadded:: 2.6
242
intercepted_unops = frozenset()
244
def intercept_unop(self, operator):
245
"""Called during template compilation with the name of a unary
246
operator to check if it should be intercepted at runtime. If this
247
method returns `True`, :meth:`call_unop` is excuted for this unary
248
operator. The default implementation of :meth:`call_unop` will use
249
the :attr:`unop_table` dictionary to perform the operator with the
250
same logic as the builtin one.
252
The following unary operators are interceptable: ``+`` and ``-``
254
Intercepted calls are always slower than the native operator call,
255
so make sure only to intercept the ones you are interested in.
257
.. versionadded:: 2.6
262
def __init__(self, *args, **kwargs):
263
Environment.__init__(self, *args, **kwargs)
264
self.globals['range'] = safe_range
265
self.binop_table = self.default_binop_table.copy()
266
self.unop_table = self.default_unop_table.copy()
268
def is_safe_attribute(self, obj, attr, value):
269
"""The sandboxed environment will call this method to check if the
270
attribute of an object is safe to access. Per default all attributes
271
starting with an underscore are considered private as well as the
272
special attributes of internal python objects as returned by the
273
:func:`is_internal_attribute` function.
275
return not (attr.startswith('_') or is_internal_attribute(obj, attr))
277
def is_safe_callable(self, obj):
278
"""Check if an object is safely callable. Per default a function is
279
considered safe unless the `unsafe_callable` attribute exists and is
280
True. Override this method to alter the behavior, but this won't
281
affect the `unsafe` decorator from this module.
283
return not (getattr(obj, 'unsafe_callable', False) or
284
getattr(obj, 'alters_data', False))
286
def call_binop(self, context, operator, left, right):
287
"""For intercepted binary operator calls (:meth:`intercepted_binops`)
288
this function is executed instead of the builtin operator. This can
289
be used to fine tune the behavior of certain operators.
291
.. versionadded:: 2.6
293
return self.binop_table[operator](left, right)
295
def call_unop(self, context, operator, arg):
296
"""For intercepted unary operator calls (:meth:`intercepted_unops`)
297
this function is executed instead of the builtin operator. This can
298
be used to fine tune the behavior of certain operators.
300
.. versionadded:: 2.6
302
return self.unop_table[operator](arg)
304
def getitem(self, obj, argument):
305
"""Subscribe an object from sandboxed code."""
308
except (TypeError, LookupError):
309
if isinstance(argument, string_types):
316
value = getattr(obj, attr)
317
except AttributeError:
320
if self.is_safe_attribute(obj, argument, value):
322
return self.unsafe_undefined(obj, argument)
323
return self.undefined(obj=obj, name=argument)
325
def getattr(self, obj, attribute):
326
"""Subscribe an object from sandboxed code and prefer the
327
attribute. The attribute passed *must* be a bytestring.
330
value = getattr(obj, attribute)
331
except AttributeError:
333
return obj[attribute]
334
except (TypeError, LookupError):
337
if self.is_safe_attribute(obj, attribute, value):
339
return self.unsafe_undefined(obj, attribute)
340
return self.undefined(obj=obj, name=attribute)
342
def unsafe_undefined(self, obj, attribute):
343
"""Return an undefined object for unsafe attributes."""
344
return self.undefined('access to attribute %r of %r '
345
'object is unsafe.' % (
347
obj.__class__.__name__
348
), name=attribute, obj=obj, exc=SecurityError)
350
def call(__self, __context, __obj, *args, **kwargs):
351
"""Call an object from sandboxed code."""
352
# the double prefixes are to avoid double keyword argument
353
# errors when proxying the call.
354
if not __self.is_safe_callable(__obj):
355
raise SecurityError('%r is not safely callable' % (__obj,))
356
return __context.call(__obj, *args, **kwargs)
359
class ImmutableSandboxedEnvironment(SandboxedEnvironment):
360
"""Works exactly like the regular `SandboxedEnvironment` but does not
361
permit modifications on the builtin mutable objects `list`, `set`, and
362
`dict` by using the :func:`modifies_known_mutable` function.
365
def is_safe_attribute(self, obj, attr, value):
366
if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value):
368
return not modifies_known_mutable(obj, attr)