blob: 3136f648dbf93a323e082234d4b9c70f5cb3394d [file] [log] [blame]
Armin Ronacherc63243e2008-04-14 22:53:58 +02001# -*- coding: utf-8 -*-
2"""
3 jinja2.sandbox
4 ~~~~~~~~~~~~~~
5
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.
9
10 The behavior can be changed by subclassing the environment.
11
Armin Ronacher55494e42010-01-22 09:41:48 +010012 :copyright: (c) 2010 by the Jinja Team.
Armin Ronacherc63243e2008-04-14 22:53:58 +020013 :license: BSD.
14"""
Armin Ronacher522cad62008-05-17 13:55:37 +020015import operator
Armin Ronacherc63243e2008-04-14 22:53:58 +020016from jinja2.environment import Environment
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +020017from jinja2.exceptions import SecurityError
Armin Ronacher9a0078d2008-08-13 18:24:17 +020018from jinja2.utils import FunctionType, MethodType, TracebackType, CodeType, \
19 FrameType, GeneratorType
Armin Ronacherc63243e2008-04-14 22:53:58 +020020
21
22#: maximum number of items a range may produce
23MAX_RANGE = 100000
24
Armin Ronacher76c280b2008-05-04 12:31:48 +020025#: attributes of function objects that are considered unsafe.
26UNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict',
27 'func_defaults', 'func_globals'])
28
29#: unsafe method attributes. function attributes are unsafe for methods too
30UNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self'])
31
Armin Ronacher522cad62008-05-17 13:55:37 +020032
Armin Ronacher51097172009-02-19 19:57:01 +010033import warnings
34
35# make sure we don't warn in python 2.6 about stuff we don't care about
36warnings.filterwarnings('ignore', 'the sets module', DeprecationWarning,
37 module='jinja2.sandbox')
38
Armin Ronacherd71fff02008-05-26 23:57:07 +020039from collections import deque
Armin Ronacher790b8a82010-02-10 00:05:46 +010040
Armin Ronacher51097172009-02-19 19:57:01 +010041_mutable_set_types = (set,)
Armin Ronacher790b8a82010-02-10 00:05:46 +010042_mutable_mapping_types = (dict,)
43_mutable_sequence_types = (list,)
44
45
46# on python 2.x we can register the user collection types
47try:
48 from UserDict import UserDict, DictMixin
49 from UserList import UserList
50 _mutable_mapping_types += (UserDict, DictMixin)
51 _mutable_set_types += (UserList,)
52except ImportError:
53 pass
Armin Ronacher522cad62008-05-17 13:55:37 +020054
Armin Ronacher51097172009-02-19 19:57:01 +010055# if sets is still available, register the mutable set from there as well
56try:
57 from sets import Set
58 _mutable_set_types += (Set,)
59except ImportError:
60 pass
61
Armin Ronacherd71fff02008-05-26 23:57:07 +020062#: register Python 2.6 abstract base classes
63try:
64 from collections import MutableSet, MutableMapping, MutableSequence
65 _mutable_set_types += (MutableSet,)
66 _mutable_mapping_types += (MutableMapping,)
67 _mutable_sequence_types += (MutableSequence,)
68except ImportError:
69 pass
70
71_mutable_spec = (
72 (_mutable_set_types, frozenset([
73 'add', 'clear', 'difference_update', 'discard', 'pop', 'remove',
74 'symmetric_difference_update', 'update'
75 ])),
76 (_mutable_mapping_types, frozenset([
77 'clear', 'pop', 'popitem', 'setdefault', 'update'
78 ])),
79 (_mutable_sequence_types, frozenset([
80 'append', 'reverse', 'insert', 'sort', 'extend', 'remove'
81 ])),
82 (deque, frozenset([
83 'append', 'appendleft', 'clear', 'extend', 'extendleft', 'pop',
84 'popleft', 'remove', 'rotate'
85 ]))
86)
Armin Ronacher522cad62008-05-17 13:55:37 +020087
Armin Ronacherc63243e2008-04-14 22:53:58 +020088
89def safe_range(*args):
90 """A range that can't generate ranges with a length of more than
Armin Ronacher7ceced52008-05-03 10:15:31 +020091 MAX_RANGE items.
92 """
Armin Ronacherc63243e2008-04-14 22:53:58 +020093 rng = xrange(*args)
94 if len(rng) > MAX_RANGE:
Armin Ronacher76c280b2008-05-04 12:31:48 +020095 raise OverflowError('range too big, maximum size for range is %d' %
96 MAX_RANGE)
Armin Ronacherc63243e2008-04-14 22:53:58 +020097 return rng
98
99
100def unsafe(f):
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200101 """
102 Mark a function or method as unsafe::
103
104 @unsafe
105 def delete(self):
106 pass
107 """
Armin Ronacherc63243e2008-04-14 22:53:58 +0200108 f.unsafe_callable = True
109 return f
110
111
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200112def 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.
117
118 >>> from jinja2.sandbox import is_internal_attribute
119 >>> is_internal_attribute(lambda: None, "func_code")
120 True
121 >>> is_internal_attribute((lambda x:x).func_code, 'co_code')
122 True
123 >>> is_internal_attribute(str, "upper")
124 False
125 """
126 if isinstance(obj, FunctionType):
Armin Ronacherd71fff02008-05-26 23:57:07 +0200127 if attr in UNSAFE_FUNCTION_ATTRIBUTES:
128 return True
129 elif isinstance(obj, MethodType):
130 if attr in UNSAFE_FUNCTION_ATTRIBUTES or \
131 attr in UNSAFE_METHOD_ATTRIBUTES:
132 return True
133 elif isinstance(obj, type):
134 if attr == 'mro':
135 return True
136 elif isinstance(obj, (CodeType, TracebackType, FrameType)):
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200137 return True
Armin Ronacherd71fff02008-05-26 23:57:07 +0200138 elif isinstance(obj, GeneratorType):
139 if attr == 'gi_frame':
140 return True
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200141 return attr.startswith('__')
142
143
Armin Ronacherd71fff02008-05-26 23:57:07 +0200144def modifies_known_mutable(obj, attr):
Armin Ronacher522cad62008-05-17 13:55:37 +0200145 """This function checks if an attribute on a builtin mutable object
Armin Ronacherd71fff02008-05-26 23:57:07 +0200146 (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`.
Armin Ronacher522cad62008-05-17 13:55:37 +0200150
Armin Ronacherd71fff02008-05-26 23:57:07 +0200151 >>> modifies_known_mutable({}, "clear")
Armin Ronacher522cad62008-05-17 13:55:37 +0200152 True
Armin Ronacherd71fff02008-05-26 23:57:07 +0200153 >>> modifies_known_mutable({}, "keys")
Armin Ronacher522cad62008-05-17 13:55:37 +0200154 False
Armin Ronacherd71fff02008-05-26 23:57:07 +0200155 >>> modifies_known_mutable([], "append")
Armin Ronacher522cad62008-05-17 13:55:37 +0200156 True
Armin Ronacherd71fff02008-05-26 23:57:07 +0200157 >>> modifies_known_mutable([], "index")
Armin Ronacher522cad62008-05-17 13:55:37 +0200158 False
159
160 If called with an unsupported object (such as unicode) `False` is
161 returned.
162
Armin Ronacherd71fff02008-05-26 23:57:07 +0200163 >>> modifies_known_mutable("foo", "upper")
Armin Ronacher522cad62008-05-17 13:55:37 +0200164 False
165 """
Armin Ronacherd71fff02008-05-26 23:57:07 +0200166 for typespec, unsafe in _mutable_spec:
167 if isinstance(obj, typespec):
168 return attr in unsafe
Armin Ronacher522cad62008-05-17 13:55:37 +0200169 return False
170
171
Armin Ronacherc63243e2008-04-14 22:53:58 +0200172class SandboxedEnvironment(Environment):
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200173 """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.
177
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.
181 """
Armin Ronacherc63243e2008-04-14 22:53:58 +0200182 sandboxed = True
183
Armin Ronachera9195382010-11-29 13:21:57 +0100184 #: 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 = {
188 '+': operator.add,
189 '-': operator.sub,
190 '*': operator.mul,
191 '/': operator.truediv,
192 '//': operator.floordiv,
193 '**': operator.pow,
194 '%': operator.mod
195 }
196
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 = {
201 '+': operator.pos,
202 '-': operator.neg
203 }
204
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`.
209 #:
210 #: The following binary operators are interceptable:
211 #: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**``
212 #:
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
216 #: interested in.
217 #:
218 #: .. versionadded:: 2.6
219 intercepted_binops = frozenset()
220
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`.
225 #:
226 #: The following unary operators are interceptable: ``+``, ``-``
227 #:
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
231 #: interested in.
232 #:
233 #: .. versionadded:: 2.6
234 intercepted_unops = frozenset()
235
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.
243
244 The following unary operators are interceptable: ``+`` and ``-``
245
246 Intercepted calls are always slower than the native operator call,
247 so make sure only to intercept the ones you are interested in.
248
249 .. versionadded:: 2.6
250 """
251 return False
252
253
Armin Ronacherc63243e2008-04-14 22:53:58 +0200254 def __init__(self, *args, **kwargs):
255 Environment.__init__(self, *args, **kwargs)
256 self.globals['range'] = safe_range
Armin Ronachera9195382010-11-29 13:21:57 +0100257 self.binop_table = self.default_binop_table.copy()
258 self.unop_table = self.default_unop_table.copy()
Armin Ronacherc63243e2008-04-14 22:53:58 +0200259
Armin Ronacher9a822052008-04-17 18:44:07 +0200260 def is_safe_attribute(self, obj, attr, value):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200261 """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
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200264 special attributes of internal python objects as returned by the
265 :func:`is_internal_attribute` function.
Armin Ronacherc63243e2008-04-14 22:53:58 +0200266 """
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200267 return not (attr.startswith('_') or is_internal_attribute(obj, attr))
Armin Ronacherc63243e2008-04-14 22:53:58 +0200268
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
Armin Ronacher7ceced52008-05-03 10:15:31 +0200272 True. Override this method to alter the behavior, but this won't
Armin Ronacherc63243e2008-04-14 22:53:58 +0200273 affect the `unsafe` decorator from this module.
274 """
Armin Ronacherd9455c12010-11-29 12:39:11 +0100275 return not (getattr(obj, 'unsafe_callable', False) or
Armin Ronacher7ceced52008-05-03 10:15:31 +0200276 getattr(obj, 'alters_data', False))
Armin Ronacherc63243e2008-04-14 22:53:58 +0200277
Armin Ronachera9195382010-11-29 13:21:57 +0100278 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.
282
283 .. versionadded:: 2.6
284 """
285 return self.binop_table[operator](left, right)
286
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.
291
292 .. versionadded:: 2.6
293 """
294 return self.unop_table[operator](arg)
295
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200296 def getitem(self, obj, argument):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200297 """Subscribe an object from sandboxed code."""
Armin Ronacher9a822052008-04-17 18:44:07 +0200298 try:
299 return obj[argument]
Armin Ronacherc63243e2008-04-14 22:53:58 +0200300 except (TypeError, LookupError):
Armin Ronacherf15f5f72008-05-26 12:21:45 +0200301 if isinstance(argument, basestring):
302 try:
303 attr = str(argument)
Ian Lewisab014bd2010-10-31 20:29:28 +0900304 except Exception:
Armin Ronacherf15f5f72008-05-26 12:21:45 +0200305 pass
306 else:
307 try:
308 value = getattr(obj, attr)
309 except AttributeError:
310 pass
311 else:
312 if self.is_safe_attribute(obj, argument, value):
313 return value
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200314 return self.unsafe_undefined(obj, argument)
Armin Ronacher9a822052008-04-17 18:44:07 +0200315 return self.undefined(obj=obj, name=argument)
Armin Ronacherc63243e2008-04-14 22:53:58 +0200316
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200317 def getattr(self, obj, attribute):
318 """Subscribe an object from sandboxed code and prefer the
319 attribute. The attribute passed *must* be a bytestring.
320 """
321 try:
322 value = getattr(obj, attribute)
323 except AttributeError:
324 try:
Armin Ronacher9efe0812008-11-02 12:22:00 +0100325 return obj[attribute]
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200326 except (TypeError, LookupError):
327 pass
328 else:
329 if self.is_safe_attribute(obj, attribute, value):
330 return value
331 return self.unsafe_undefined(obj, attribute)
Armin Ronacher9efe0812008-11-02 12:22:00 +0100332 return self.undefined(obj=obj, name=attribute)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200333
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.' % (
338 attribute,
339 obj.__class__.__name__
340 ), name=attribute, obj=obj, exc=SecurityError)
341
Armin Ronacherfd310492008-05-25 00:16:51 +0200342 def call(__self, __context, __obj, *args, **kwargs):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200343 """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):
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200347 raise SecurityError('%r is not safely callable' % (__obj,))
Armin Ronacherfd310492008-05-25 00:16:51 +0200348 return __context.call(__obj, *args, **kwargs)
Armin Ronacher522cad62008-05-17 13:55:37 +0200349
350
351class ImmutableSandboxedEnvironment(SandboxedEnvironment):
352 """Works exactly like the regular `SandboxedEnvironment` but does not
353 permit modifications on the builtin mutable objects `list`, `set`, and
Armin Ronacherd71fff02008-05-26 23:57:07 +0200354 `dict` by using the :func:`modifies_known_mutable` function.
Armin Ronacher522cad62008-05-17 13:55:37 +0200355 """
356
357 def is_safe_attribute(self, obj, attr, value):
358 if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value):
359 return False
Armin Ronacherd71fff02008-05-26 23:57:07 +0200360 return not modifies_known_mutable(obj, attr)