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) 2009 by the Jinja Team.
16 from jinja2.runtime import Undefined
17 from jinja2.environment import Environment
18 from jinja2.exceptions import SecurityError
19 from jinja2.utils import FunctionType, MethodType, TracebackType, CodeType, \
20 FrameType, GeneratorType
23 #: maximum number of items a range may produce
26 #: attributes of function objects that are considered unsafe.
27 UNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict',
28 'func_defaults', 'func_globals'])
30 #: unsafe method attributes. function attributes are unsafe for methods too
31 UNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self'])
36 # make sure we don't warn in python 2.6 about stuff we don't care about
37 warnings.filterwarnings('ignore', 'the sets module', DeprecationWarning,
38 module='jinja2.sandbox')
41 from collections import deque
42 from UserDict import UserDict, DictMixin
43 from UserList import UserList
44 _mutable_set_types = (set,)
45 _mutable_mapping_types = (UserDict, DictMixin, dict)
46 _mutable_sequence_types = (UserList, list)
48 # if sets is still available, register the mutable set from there as well
51 _mutable_set_types += (Set,)
55 #: register Python 2.6 abstract base classes
57 from collections import MutableSet, MutableMapping, MutableSequence
58 _mutable_set_types += (MutableSet,)
59 _mutable_mapping_types += (MutableMapping,)
60 _mutable_sequence_types += (MutableSequence,)
65 (_mutable_set_types, frozenset([
66 'add', 'clear', 'difference_update', 'discard', 'pop', 'remove',
67 'symmetric_difference_update', 'update'
69 (_mutable_mapping_types, frozenset([
70 'clear', 'pop', 'popitem', 'setdefault', 'update'
72 (_mutable_sequence_types, frozenset([
73 'append', 'reverse', 'insert', 'sort', 'extend', 'remove'
76 'append', 'appendleft', 'clear', 'extend', 'extendleft', 'pop',
77 'popleft', 'remove', 'rotate'
82 def safe_range(*args):
83 """A range that can't generate ranges with a length of more than
87 if len(rng) > MAX_RANGE:
88 raise OverflowError('range too big, maximum size for range is %d' %
95 Mark a function or method as unsafe::
101 f.unsafe_callable = True
105 def is_internal_attribute(obj, attr):
106 """Test if the attribute given is an internal python attribute. For
107 example this function returns `True` for the `func_code` attribute of
108 python objects. This is useful if the environment method
109 :meth:`~SandboxedEnvironment.is_safe_attribute` is overriden.
111 >>> from jinja2.sandbox import is_internal_attribute
112 >>> is_internal_attribute(lambda: None, "func_code")
114 >>> is_internal_attribute((lambda x:x).func_code, 'co_code')
116 >>> is_internal_attribute(str, "upper")
119 if isinstance(obj, FunctionType):
120 if attr in UNSAFE_FUNCTION_ATTRIBUTES:
122 elif isinstance(obj, MethodType):
123 if attr in UNSAFE_FUNCTION_ATTRIBUTES or \
124 attr in UNSAFE_METHOD_ATTRIBUTES:
126 elif isinstance(obj, type):
129 elif isinstance(obj, (CodeType, TracebackType, FrameType)):
131 elif isinstance(obj, GeneratorType):
132 if attr == 'gi_frame':
134 return attr.startswith('__')
137 def modifies_known_mutable(obj, attr):
138 """This function checks if an attribute on a builtin mutable object
139 (list, dict, set or deque) would modify it if called. It also supports
140 the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and
141 with Python 2.6 onwards the abstract base classes `MutableSet`,
142 `MutableMapping`, and `MutableSequence`.
144 >>> modifies_known_mutable({}, "clear")
146 >>> modifies_known_mutable({}, "keys")
148 >>> modifies_known_mutable([], "append")
150 >>> modifies_known_mutable([], "index")
153 If called with an unsupported object (such as unicode) `False` is
156 >>> modifies_known_mutable("foo", "upper")
159 for typespec, unsafe in _mutable_spec:
160 if isinstance(obj, typespec):
161 return attr in unsafe
165 class SandboxedEnvironment(Environment):
166 """The sandboxed environment. It works like the regular environment but
167 tells the compiler to generate sandboxed code. Additionally subclasses of
168 this environment may override the methods that tell the runtime what
169 attributes or functions are safe to access.
171 If the template tries to access insecure code a :exc:`SecurityError` is
172 raised. However also other exceptions may occour during the rendering so
173 the caller has to ensure that all exceptions are catched.
177 def __init__(self, *args, **kwargs):
178 Environment.__init__(self, *args, **kwargs)
179 self.globals['range'] = safe_range
181 def is_safe_attribute(self, obj, attr, value):
182 """The sandboxed environment will call this method to check if the
183 attribute of an object is safe to access. Per default all attributes
184 starting with an underscore are considered private as well as the
185 special attributes of internal python objects as returned by the
186 :func:`is_internal_attribute` function.
188 return not (attr.startswith('_') or is_internal_attribute(obj, attr))
190 def is_safe_callable(self, obj):
191 """Check if an object is safely callable. Per default a function is
192 considered safe unless the `unsafe_callable` attribute exists and is
193 True. Override this method to alter the behavior, but this won't
194 affect the `unsafe` decorator from this module.
196 return not (getattr(obj, 'unsafe_callable', False) or \
197 getattr(obj, 'alters_data', False))
199 def getitem(self, obj, argument):
200 """Subscribe an object from sandboxed code."""
203 except (TypeError, LookupError):
204 if isinstance(argument, basestring):
211 value = getattr(obj, attr)
212 except AttributeError:
215 if self.is_safe_attribute(obj, argument, value):
217 return self.unsafe_undefined(obj, argument)
218 return self.undefined(obj=obj, name=argument)
220 def getattr(self, obj, attribute):
221 """Subscribe an object from sandboxed code and prefer the
222 attribute. The attribute passed *must* be a bytestring.
225 value = getattr(obj, attribute)
226 except AttributeError:
228 return obj[attribute]
229 except (TypeError, LookupError):
232 if self.is_safe_attribute(obj, attribute, value):
234 return self.unsafe_undefined(obj, attribute)
235 return self.undefined(obj=obj, name=attribute)
237 def unsafe_undefined(self, obj, attribute):
238 """Return an undefined object for unsafe attributes."""
239 return self.undefined('access to attribute %r of %r '
240 'object is unsafe.' % (
242 obj.__class__.__name__
243 ), name=attribute, obj=obj, exc=SecurityError)
245 def call(__self, __context, __obj, *args, **kwargs):
246 """Call an object from sandboxed code."""
247 # the double prefixes are to avoid double keyword argument
248 # errors when proxying the call.
249 if not __self.is_safe_callable(__obj):
250 raise SecurityError('%r is not safely callable' % (__obj,))
251 return __context.call(__obj, *args, **kwargs)
254 class ImmutableSandboxedEnvironment(SandboxedEnvironment):
255 """Works exactly like the regular `SandboxedEnvironment` but does not
256 permit modifications on the builtin mutable objects `list`, `set`, and
257 `dict` by using the :func:`modifies_known_mutable` function.
260 def is_safe_attribute(self, obj, attr, value):
261 if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value):
263 return not modifies_known_mutable(obj, attr)