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' %
101 """Marks a function or method as unsafe.
109 f.unsafe_callable = True
113 def is_internal_attribute(obj, attr):
114 """Test if the attribute given is an internal python attribute. For
115 example this function returns `True` for the `func_code` attribute of
116 python objects. This is useful if the environment method
117 :meth:`~SandboxedEnvironment.is_safe_attribute` is overriden.
119 >>> from jinja2.sandbox import is_internal_attribute
120 >>> is_internal_attribute(lambda: None, "func_code")
122 >>> is_internal_attribute((lambda x:x).func_code, 'co_code')
124 >>> is_internal_attribute(str, "upper")
127 if isinstance(obj, FunctionType):
128 if attr in UNSAFE_FUNCTION_ATTRIBUTES:
130 elif isinstance(obj, MethodType):
131 if attr in UNSAFE_FUNCTION_ATTRIBUTES or \
132 attr in UNSAFE_METHOD_ATTRIBUTES:
134 elif isinstance(obj, type):
137 elif isinstance(obj, (CodeType, TracebackType, FrameType)):
139 elif isinstance(obj, GeneratorType):
140 if attr == 'gi_frame':
142 return attr.startswith('__')
145 def modifies_known_mutable(obj, attr):
146 """This function checks if an attribute on a builtin mutable object
147 (list, dict, set or deque) would modify it if called. It also supports
148 the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and
149 with Python 2.6 onwards the abstract base classes `MutableSet`,
150 `MutableMapping`, and `MutableSequence`.
152 >>> modifies_known_mutable({}, "clear")
154 >>> modifies_known_mutable({}, "keys")
156 >>> modifies_known_mutable([], "append")
158 >>> modifies_known_mutable([], "index")
161 If called with an unsupported object (such as unicode) `False` is
164 >>> modifies_known_mutable("foo", "upper")
167 for typespec, unsafe in _mutable_spec:
168 if isinstance(obj, typespec):
169 return attr in unsafe
173 class SandboxedEnvironment(Environment):
174 """The sandboxed environment. It works like the regular environment but
175 tells the compiler to generate sandboxed code. Additionally subclasses of
176 this environment may override the methods that tell the runtime what
177 attributes or functions are safe to access.
179 If the template tries to access insecure code a :exc:`SecurityError` is
180 raised. However also other exceptions may occour during the rendering so
181 the caller has to ensure that all exceptions are catched.
185 #: default callback table for the binary operators. A copy of this is
186 #: available on each instance of a sandboxed environment as
187 #: :attr:`binop_table`
188 default_binop_table = {
192 '/': operator.truediv,
193 '//': operator.floordiv,
198 #: default callback table for the unary operators. A copy of this is
199 #: available on each instance of a sandboxed environment as
200 #: :attr:`unop_table`
201 default_unop_table = {
206 #: a set of binary operators that should be intercepted. Each operator
207 #: that is added to this set (empty by default) is delegated to the
208 #: :meth:`call_binop` method that will perform the operator. The default
209 #: operator callback is specified by :attr:`binop_table`.
211 #: The following binary operators are interceptable:
212 #: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**``
214 #: The default operation form the operator table corresponds to the
215 #: builtin function. Intercepted calls are always slower than the native
216 #: operator call, so make sure only to intercept the ones you are
219 #: .. versionadded:: 2.6
220 intercepted_binops = frozenset()
222 #: a set of unary operators that should be intercepted. Each operator
223 #: that is added to this set (empty by default) is delegated to the
224 #: :meth:`call_unop` method that will perform the operator. The default
225 #: operator callback is specified by :attr:`unop_table`.
227 #: The following unary operators are interceptable: ``+``, ``-``
229 #: The default operation form the operator table corresponds to the
230 #: builtin function. Intercepted calls are always slower than the native
231 #: operator call, so make sure only to intercept the ones you are
234 #: .. versionadded:: 2.6
235 intercepted_unops = frozenset()
237 def intercept_unop(self, operator):
238 """Called during template compilation with the name of a unary
239 operator to check if it should be intercepted at runtime. If this
240 method returns `True`, :meth:`call_unop` is excuted for this unary
241 operator. The default implementation of :meth:`call_unop` will use
242 the :attr:`unop_table` dictionary to perform the operator with the
243 same logic as the builtin one.
245 The following unary operators are interceptable: ``+`` and ``-``
247 Intercepted calls are always slower than the native operator call,
248 so make sure only to intercept the ones you are interested in.
250 .. versionadded:: 2.6
255 def __init__(self, *args, **kwargs):
256 Environment.__init__(self, *args, **kwargs)
257 self.globals['range'] = safe_range
258 self.binop_table = self.default_binop_table.copy()
259 self.unop_table = self.default_unop_table.copy()
261 def is_safe_attribute(self, obj, attr, value):
262 """The sandboxed environment will call this method to check if the
263 attribute of an object is safe to access. Per default all attributes
264 starting with an underscore are considered private as well as the
265 special attributes of internal python objects as returned by the
266 :func:`is_internal_attribute` function.
268 return not (attr.startswith('_') or is_internal_attribute(obj, attr))
270 def is_safe_callable(self, obj):
271 """Check if an object is safely callable. Per default a function is
272 considered safe unless the `unsafe_callable` attribute exists and is
273 True. Override this method to alter the behavior, but this won't
274 affect the `unsafe` decorator from this module.
276 return not (getattr(obj, 'unsafe_callable', False) or
277 getattr(obj, 'alters_data', False))
279 def call_binop(self, context, operator, left, right):
280 """For intercepted binary operator calls (:meth:`intercepted_binops`)
281 this function is executed instead of the builtin operator. This can
282 be used to fine tune the behavior of certain operators.
284 .. versionadded:: 2.6
286 return self.binop_table[operator](left, right)
288 def call_unop(self, context, operator, arg):
289 """For intercepted unary operator calls (:meth:`intercepted_unops`)
290 this function is executed instead of the builtin operator. This can
291 be used to fine tune the behavior of certain operators.
293 .. versionadded:: 2.6
295 return self.unop_table[operator](arg)
297 def getitem(self, obj, argument):
298 """Subscribe an object from sandboxed code."""
301 except (TypeError, LookupError):
302 if isinstance(argument, basestring):
309 value = getattr(obj, attr)
310 except AttributeError:
313 if self.is_safe_attribute(obj, argument, value):
315 return self.unsafe_undefined(obj, argument)
316 return self.undefined(obj=obj, name=argument)
318 def getattr(self, obj, attribute):
319 """Subscribe an object from sandboxed code and prefer the
320 attribute. The attribute passed *must* be a bytestring.
323 value = getattr(obj, attribute)
324 except AttributeError:
326 return obj[attribute]
327 except (TypeError, LookupError):
330 if self.is_safe_attribute(obj, attribute, value):
332 return self.unsafe_undefined(obj, attribute)
333 return self.undefined(obj=obj, name=attribute)
335 def unsafe_undefined(self, obj, attribute):
336 """Return an undefined object for unsafe attributes."""
337 return self.undefined('access to attribute %r of %r '
338 'object is unsafe.' % (
340 obj.__class__.__name__
341 ), name=attribute, obj=obj, exc=SecurityError)
343 def call(__self, __context, __obj, *args, **kwargs):
344 """Call an object from sandboxed code."""
345 # the double prefixes are to avoid double keyword argument
346 # errors when proxying the call.
347 if not __self.is_safe_callable(__obj):
348 raise SecurityError('%r is not safely callable' % (__obj,))
349 return __context.call(__obj, *args, **kwargs)
352 class ImmutableSandboxedEnvironment(SandboxedEnvironment):
353 """Works exactly like the regular `SandboxedEnvironment` but does not
354 permit modifications on the builtin mutable objects `list`, `set`, and
355 `dict` by using the :func:`modifies_known_mutable` function.
358 def is_safe_attribute(self, obj, attr, value):
359 if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value):
361 return not modifies_known_mutable(obj, attr)