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.utils import FunctionType, MethodType, TracebackType, CodeType, \
19 FrameType, GeneratorType
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'])
35 # make sure we don't warn in python 2.6 about stuff we don't care about
36 warnings.filterwarnings('ignore', 'the sets module', DeprecationWarning,
37 module='jinja2.sandbox')
39 from collections import deque
41 _mutable_set_types = (set,)
42 _mutable_mapping_types = (dict,)
43 _mutable_sequence_types = (list,)
46 # on python 2.x we can register the user collection types
48 from UserDict import UserDict, DictMixin
49 from UserList import UserList
50 _mutable_mapping_types += (UserDict, DictMixin)
51 _mutable_set_types += (UserList,)
55 # if sets is still available, register the mutable set from there as well
58 _mutable_set_types += (Set,)
62 #: register Python 2.6 abstract base classes
64 from collections import MutableSet, MutableMapping, MutableSequence
65 _mutable_set_types += (MutableSet,)
66 _mutable_mapping_types += (MutableMapping,)
67 _mutable_sequence_types += (MutableSequence,)
72 (_mutable_set_types, frozenset([
73 'add', 'clear', 'difference_update', 'discard', 'pop', 'remove',
74 'symmetric_difference_update', 'update'
76 (_mutable_mapping_types, frozenset([
77 'clear', 'pop', 'popitem', 'setdefault', 'update'
79 (_mutable_sequence_types, frozenset([
80 'append', 'reverse', 'insert', 'sort', 'extend', 'remove'
83 'append', 'appendleft', 'clear', 'extend', 'extendleft', 'pop',
84 'popleft', 'remove', 'rotate'
89 def safe_range(*args):
90 """A range that can't generate ranges with a length of more than
94 if len(rng) > MAX_RANGE:
95 raise OverflowError('range too big, maximum size for range is %d' %
102 Mark a function or method as unsafe::
108 f.unsafe_callable = True
112 def is_internal_attribute(obj, attr):
113 """Test if the attribute given is an internal python attribute. For
114 example this function returns `True` for the `func_code` attribute of
115 python objects. This is useful if the environment method
116 :meth:`~SandboxedEnvironment.is_safe_attribute` is overriden.
118 >>> from jinja2.sandbox import is_internal_attribute
119 >>> is_internal_attribute(lambda: None, "func_code")
121 >>> is_internal_attribute((lambda x:x).func_code, 'co_code')
123 >>> is_internal_attribute(str, "upper")
126 if isinstance(obj, FunctionType):
127 if attr in UNSAFE_FUNCTION_ATTRIBUTES:
129 elif isinstance(obj, MethodType):
130 if attr in UNSAFE_FUNCTION_ATTRIBUTES or \
131 attr in UNSAFE_METHOD_ATTRIBUTES:
133 elif isinstance(obj, type):
136 elif isinstance(obj, (CodeType, TracebackType, FrameType)):
138 elif isinstance(obj, GeneratorType):
139 if attr == 'gi_frame':
141 return attr.startswith('__')
144 def modifies_known_mutable(obj, attr):
145 """This function checks if an attribute on a builtin mutable object
146 (list, dict, set or deque) would modify it if called. It also supports
147 the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and
148 with Python 2.6 onwards the abstract base classes `MutableSet`,
149 `MutableMapping`, and `MutableSequence`.
151 >>> modifies_known_mutable({}, "clear")
153 >>> modifies_known_mutable({}, "keys")
155 >>> modifies_known_mutable([], "append")
157 >>> modifies_known_mutable([], "index")
160 If called with an unsupported object (such as unicode) `False` is
163 >>> modifies_known_mutable("foo", "upper")
166 for typespec, unsafe in _mutable_spec:
167 if isinstance(obj, typespec):
168 return attr in unsafe
172 class SandboxedEnvironment(Environment):
173 """The sandboxed environment. It works like the regular environment but
174 tells the compiler to generate sandboxed code. Additionally subclasses of
175 this environment may override the methods that tell the runtime what
176 attributes or functions are safe to access.
178 If the template tries to access insecure code a :exc:`SecurityError` is
179 raised. However also other exceptions may occour during the rendering so
180 the caller has to ensure that all exceptions are catched.
184 #: default callback table for the binary operators. A copy of this is
185 #: available on each instance of a sandboxed environment as
186 #: :attr:`binop_table`
187 default_binop_table = {
191 '/': operator.truediv,
192 '//': operator.floordiv,
197 #: default callback table for the unary operators. A copy of this is
198 #: available on each instance of a sandboxed environment as
199 #: :attr:`unop_table`
200 default_unop_table = {
205 #: a set of binary operators that should be intercepted. Each operator
206 #: that is added to this set (empty by default) is delegated to the
207 #: :meth:`call_binop` method that will perform the operator. The default
208 #: operator callback is specified by :attr:`binop_table`.
210 #: The following binary operators are interceptable:
211 #: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**``
213 #: The default operation form the operator table corresponds to the
214 #: builtin function. Intercepted calls are always slower than the native
215 #: operator call, so make sure only to intercept the ones you are
218 #: .. versionadded:: 2.6
219 intercepted_binops = frozenset()
221 #: a set of unary operators that should be intercepted. Each operator
222 #: that is added to this set (empty by default) is delegated to the
223 #: :meth:`call_unop` method that will perform the operator. The default
224 #: operator callback is specified by :attr:`unop_table`.
226 #: The following unary operators are interceptable: ``+``, ``-``
228 #: The default operation form the operator table corresponds to the
229 #: builtin function. Intercepted calls are always slower than the native
230 #: operator call, so make sure only to intercept the ones you are
233 #: .. versionadded:: 2.6
234 intercepted_unops = frozenset()
236 def intercept_unop(self, operator):
237 """Called during template compilation with the name of a unary
238 operator to check if it should be intercepted at runtime. If this
239 method returns `True`, :meth:`call_unop` is excuted for this unary
240 operator. The default implementation of :meth:`call_unop` will use
241 the :attr:`unop_table` dictionary to perform the operator with the
242 same logic as the builtin one.
244 The following unary operators are interceptable: ``+`` and ``-``
246 Intercepted calls are always slower than the native operator call,
247 so make sure only to intercept the ones you are interested in.
249 .. versionadded:: 2.6
254 def __init__(self, *args, **kwargs):
255 Environment.__init__(self, *args, **kwargs)
256 self.globals['range'] = safe_range
257 self.binop_table = self.default_binop_table.copy()
258 self.unop_table = self.default_unop_table.copy()
260 def is_safe_attribute(self, obj, attr, value):
261 """The sandboxed environment will call this method to check if the
262 attribute of an object is safe to access. Per default all attributes
263 starting with an underscore are considered private as well as the
264 special attributes of internal python objects as returned by the
265 :func:`is_internal_attribute` function.
267 return not (attr.startswith('_') or is_internal_attribute(obj, attr))
269 def is_safe_callable(self, obj):
270 """Check if an object is safely callable. Per default a function is
271 considered safe unless the `unsafe_callable` attribute exists and is
272 True. Override this method to alter the behavior, but this won't
273 affect the `unsafe` decorator from this module.
275 return not (getattr(obj, 'unsafe_callable', False) or
276 getattr(obj, 'alters_data', False))
278 def call_binop(self, context, operator, left, right):
279 """For intercepted binary operator calls (:meth:`intercepted_binops`)
280 this function is executed instead of the builtin operator. This can
281 be used to fine tune the behavior of certain operators.
283 .. versionadded:: 2.6
285 return self.binop_table[operator](left, right)
287 def call_unop(self, context, operator, arg):
288 """For intercepted unary operator calls (:meth:`intercepted_unops`)
289 this function is executed instead of the builtin operator. This can
290 be used to fine tune the behavior of certain operators.
292 .. versionadded:: 2.6
294 return self.unop_table[operator](arg)
296 def getitem(self, obj, argument):
297 """Subscribe an object from sandboxed code."""
300 except (TypeError, LookupError):
301 if isinstance(argument, basestring):
308 value = getattr(obj, attr)
309 except AttributeError:
312 if self.is_safe_attribute(obj, argument, value):
314 return self.unsafe_undefined(obj, argument)
315 return self.undefined(obj=obj, name=argument)
317 def getattr(self, obj, attribute):
318 """Subscribe an object from sandboxed code and prefer the
319 attribute. The attribute passed *must* be a bytestring.
322 value = getattr(obj, attribute)
323 except AttributeError:
325 return obj[attribute]
326 except (TypeError, LookupError):
329 if self.is_safe_attribute(obj, attribute, value):
331 return self.unsafe_undefined(obj, attribute)
332 return self.undefined(obj=obj, name=attribute)
334 def unsafe_undefined(self, obj, attribute):
335 """Return an undefined object for unsafe attributes."""
336 return self.undefined('access to attribute %r of %r '
337 'object is unsafe.' % (
339 obj.__class__.__name__
340 ), name=attribute, obj=obj, exc=SecurityError)
342 def call(__self, __context, __obj, *args, **kwargs):
343 """Call an object from sandboxed code."""
344 # the double prefixes are to avoid double keyword argument
345 # errors when proxying the call.
346 if not __self.is_safe_callable(__obj):
347 raise SecurityError('%r is not safely callable' % (__obj,))
348 return __context.call(__obj, *args, **kwargs)
351 class ImmutableSandboxedEnvironment(SandboxedEnvironment):
352 """Works exactly like the regular `SandboxedEnvironment` but does not
353 permit modifications on the builtin mutable objects `list`, `set`, and
354 `dict` by using the :func:`modifies_known_mutable` function.
357 def is_safe_attribute(self, obj, attr, value):
358 if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value):
360 return not modifies_known_mutable(obj, attr)