comparison env/lib/python3.9/site-packages/jinja2/sandbox.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 # -*- coding: utf-8 -*-
2 """A sandbox layer that ensures unsafe operations cannot be performed.
3 Useful when the template itself comes from an untrusted source.
4 """
5 import operator
6 import types
7 import warnings
8 from collections import deque
9 from string import Formatter
10
11 from markupsafe import EscapeFormatter
12 from markupsafe import Markup
13
14 from ._compat import abc
15 from ._compat import PY2
16 from ._compat import range_type
17 from ._compat import string_types
18 from .environment import Environment
19 from .exceptions import SecurityError
20
21 #: maximum number of items a range may produce
22 MAX_RANGE = 100000
23
24 #: attributes of function objects that are considered unsafe.
25 if PY2:
26 UNSAFE_FUNCTION_ATTRIBUTES = {
27 "func_closure",
28 "func_code",
29 "func_dict",
30 "func_defaults",
31 "func_globals",
32 }
33 else:
34 # On versions > python 2 the special attributes on functions are gone,
35 # but they remain on methods and generators for whatever reason.
36 UNSAFE_FUNCTION_ATTRIBUTES = set()
37
38 #: unsafe method attributes. function attributes are unsafe for methods too
39 UNSAFE_METHOD_ATTRIBUTES = {"im_class", "im_func", "im_self"}
40
41 #: unsafe generator attributes.
42 UNSAFE_GENERATOR_ATTRIBUTES = {"gi_frame", "gi_code"}
43
44 #: unsafe attributes on coroutines
45 UNSAFE_COROUTINE_ATTRIBUTES = {"cr_frame", "cr_code"}
46
47 #: unsafe attributes on async generators
48 UNSAFE_ASYNC_GENERATOR_ATTRIBUTES = {"ag_code", "ag_frame"}
49
50 # make sure we don't warn in python 2.6 about stuff we don't care about
51 warnings.filterwarnings(
52 "ignore", "the sets module", DeprecationWarning, module=__name__
53 )
54
55 _mutable_set_types = (set,)
56 _mutable_mapping_types = (dict,)
57 _mutable_sequence_types = (list,)
58
59 # on python 2.x we can register the user collection types
60 try:
61 from UserDict import UserDict, DictMixin
62 from UserList import UserList
63
64 _mutable_mapping_types += (UserDict, DictMixin)
65 _mutable_set_types += (UserList,)
66 except ImportError:
67 pass
68
69 # if sets is still available, register the mutable set from there as well
70 try:
71 from sets import Set
72
73 _mutable_set_types += (Set,)
74 except ImportError:
75 pass
76
77 #: register Python 2.6 abstract base classes
78 _mutable_set_types += (abc.MutableSet,)
79 _mutable_mapping_types += (abc.MutableMapping,)
80 _mutable_sequence_types += (abc.MutableSequence,)
81
82 _mutable_spec = (
83 (
84 _mutable_set_types,
85 frozenset(
86 [
87 "add",
88 "clear",
89 "difference_update",
90 "discard",
91 "pop",
92 "remove",
93 "symmetric_difference_update",
94 "update",
95 ]
96 ),
97 ),
98 (
99 _mutable_mapping_types,
100 frozenset(["clear", "pop", "popitem", "setdefault", "update"]),
101 ),
102 (
103 _mutable_sequence_types,
104 frozenset(["append", "reverse", "insert", "sort", "extend", "remove"]),
105 ),
106 (
107 deque,
108 frozenset(
109 [
110 "append",
111 "appendleft",
112 "clear",
113 "extend",
114 "extendleft",
115 "pop",
116 "popleft",
117 "remove",
118 "rotate",
119 ]
120 ),
121 ),
122 )
123
124
125 class _MagicFormatMapping(abc.Mapping):
126 """This class implements a dummy wrapper to fix a bug in the Python
127 standard library for string formatting.
128
129 See https://bugs.python.org/issue13598 for information about why
130 this is necessary.
131 """
132
133 def __init__(self, args, kwargs):
134 self._args = args
135 self._kwargs = kwargs
136 self._last_index = 0
137
138 def __getitem__(self, key):
139 if key == "":
140 idx = self._last_index
141 self._last_index += 1
142 try:
143 return self._args[idx]
144 except LookupError:
145 pass
146 key = str(idx)
147 return self._kwargs[key]
148
149 def __iter__(self):
150 return iter(self._kwargs)
151
152 def __len__(self):
153 return len(self._kwargs)
154
155
156 def inspect_format_method(callable):
157 if not isinstance(
158 callable, (types.MethodType, types.BuiltinMethodType)
159 ) or callable.__name__ not in ("format", "format_map"):
160 return None
161 obj = callable.__self__
162 if isinstance(obj, string_types):
163 return obj
164
165
166 def safe_range(*args):
167 """A range that can't generate ranges with a length of more than
168 MAX_RANGE items.
169 """
170 rng = range_type(*args)
171
172 if len(rng) > MAX_RANGE:
173 raise OverflowError(
174 "Range too big. The sandbox blocks ranges larger than"
175 " MAX_RANGE (%d)." % MAX_RANGE
176 )
177
178 return rng
179
180
181 def unsafe(f):
182 """Marks a function or method as unsafe.
183
184 ::
185
186 @unsafe
187 def delete(self):
188 pass
189 """
190 f.unsafe_callable = True
191 return f
192
193
194 def is_internal_attribute(obj, attr):
195 """Test if the attribute given is an internal python attribute. For
196 example this function returns `True` for the `func_code` attribute of
197 python objects. This is useful if the environment method
198 :meth:`~SandboxedEnvironment.is_safe_attribute` is overridden.
199
200 >>> from jinja2.sandbox import is_internal_attribute
201 >>> is_internal_attribute(str, "mro")
202 True
203 >>> is_internal_attribute(str, "upper")
204 False
205 """
206 if isinstance(obj, types.FunctionType):
207 if attr in UNSAFE_FUNCTION_ATTRIBUTES:
208 return True
209 elif isinstance(obj, types.MethodType):
210 if attr in UNSAFE_FUNCTION_ATTRIBUTES or attr in UNSAFE_METHOD_ATTRIBUTES:
211 return True
212 elif isinstance(obj, type):
213 if attr == "mro":
214 return True
215 elif isinstance(obj, (types.CodeType, types.TracebackType, types.FrameType)):
216 return True
217 elif isinstance(obj, types.GeneratorType):
218 if attr in UNSAFE_GENERATOR_ATTRIBUTES:
219 return True
220 elif hasattr(types, "CoroutineType") and isinstance(obj, types.CoroutineType):
221 if attr in UNSAFE_COROUTINE_ATTRIBUTES:
222 return True
223 elif hasattr(types, "AsyncGeneratorType") and isinstance(
224 obj, types.AsyncGeneratorType
225 ):
226 if attr in UNSAFE_ASYNC_GENERATOR_ATTRIBUTES:
227 return True
228 return attr.startswith("__")
229
230
231 def modifies_known_mutable(obj, attr):
232 """This function checks if an attribute on a builtin mutable object
233 (list, dict, set or deque) would modify it if called. It also supports
234 the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and
235 with Python 2.6 onwards the abstract base classes `MutableSet`,
236 `MutableMapping`, and `MutableSequence`.
237
238 >>> modifies_known_mutable({}, "clear")
239 True
240 >>> modifies_known_mutable({}, "keys")
241 False
242 >>> modifies_known_mutable([], "append")
243 True
244 >>> modifies_known_mutable([], "index")
245 False
246
247 If called with an unsupported object (such as unicode) `False` is
248 returned.
249
250 >>> modifies_known_mutable("foo", "upper")
251 False
252 """
253 for typespec, unsafe in _mutable_spec:
254 if isinstance(obj, typespec):
255 return attr in unsafe
256 return False
257
258
259 class SandboxedEnvironment(Environment):
260 """The sandboxed environment. It works like the regular environment but
261 tells the compiler to generate sandboxed code. Additionally subclasses of
262 this environment may override the methods that tell the runtime what
263 attributes or functions are safe to access.
264
265 If the template tries to access insecure code a :exc:`SecurityError` is
266 raised. However also other exceptions may occur during the rendering so
267 the caller has to ensure that all exceptions are caught.
268 """
269
270 sandboxed = True
271
272 #: default callback table for the binary operators. A copy of this is
273 #: available on each instance of a sandboxed environment as
274 #: :attr:`binop_table`
275 default_binop_table = {
276 "+": operator.add,
277 "-": operator.sub,
278 "*": operator.mul,
279 "/": operator.truediv,
280 "//": operator.floordiv,
281 "**": operator.pow,
282 "%": operator.mod,
283 }
284
285 #: default callback table for the unary operators. A copy of this is
286 #: available on each instance of a sandboxed environment as
287 #: :attr:`unop_table`
288 default_unop_table = {"+": operator.pos, "-": operator.neg}
289
290 #: a set of binary operators that should be intercepted. Each operator
291 #: that is added to this set (empty by default) is delegated to the
292 #: :meth:`call_binop` method that will perform the operator. The default
293 #: operator callback is specified by :attr:`binop_table`.
294 #:
295 #: The following binary operators are interceptable:
296 #: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**``
297 #:
298 #: The default operation form the operator table corresponds to the
299 #: builtin function. Intercepted calls are always slower than the native
300 #: operator call, so make sure only to intercept the ones you are
301 #: interested in.
302 #:
303 #: .. versionadded:: 2.6
304 intercepted_binops = frozenset()
305
306 #: a set of unary operators that should be intercepted. Each operator
307 #: that is added to this set (empty by default) is delegated to the
308 #: :meth:`call_unop` method that will perform the operator. The default
309 #: operator callback is specified by :attr:`unop_table`.
310 #:
311 #: The following unary operators are interceptable: ``+``, ``-``
312 #:
313 #: The default operation form the operator table corresponds to the
314 #: builtin function. Intercepted calls are always slower than the native
315 #: operator call, so make sure only to intercept the ones you are
316 #: interested in.
317 #:
318 #: .. versionadded:: 2.6
319 intercepted_unops = frozenset()
320
321 def intercept_unop(self, operator):
322 """Called during template compilation with the name of a unary
323 operator to check if it should be intercepted at runtime. If this
324 method returns `True`, :meth:`call_unop` is executed for this unary
325 operator. The default implementation of :meth:`call_unop` will use
326 the :attr:`unop_table` dictionary to perform the operator with the
327 same logic as the builtin one.
328
329 The following unary operators are interceptable: ``+`` and ``-``
330
331 Intercepted calls are always slower than the native operator call,
332 so make sure only to intercept the ones you are interested in.
333
334 .. versionadded:: 2.6
335 """
336 return False
337
338 def __init__(self, *args, **kwargs):
339 Environment.__init__(self, *args, **kwargs)
340 self.globals["range"] = safe_range
341 self.binop_table = self.default_binop_table.copy()
342 self.unop_table = self.default_unop_table.copy()
343
344 def is_safe_attribute(self, obj, attr, value):
345 """The sandboxed environment will call this method to check if the
346 attribute of an object is safe to access. Per default all attributes
347 starting with an underscore are considered private as well as the
348 special attributes of internal python objects as returned by the
349 :func:`is_internal_attribute` function.
350 """
351 return not (attr.startswith("_") or is_internal_attribute(obj, attr))
352
353 def is_safe_callable(self, obj):
354 """Check if an object is safely callable. Per default a function is
355 considered safe unless the `unsafe_callable` attribute exists and is
356 True. Override this method to alter the behavior, but this won't
357 affect the `unsafe` decorator from this module.
358 """
359 return not (
360 getattr(obj, "unsafe_callable", False) or getattr(obj, "alters_data", False)
361 )
362
363 def call_binop(self, context, operator, left, right):
364 """For intercepted binary operator calls (:meth:`intercepted_binops`)
365 this function is executed instead of the builtin operator. This can
366 be used to fine tune the behavior of certain operators.
367
368 .. versionadded:: 2.6
369 """
370 return self.binop_table[operator](left, right)
371
372 def call_unop(self, context, operator, arg):
373 """For intercepted unary operator calls (:meth:`intercepted_unops`)
374 this function is executed instead of the builtin operator. This can
375 be used to fine tune the behavior of certain operators.
376
377 .. versionadded:: 2.6
378 """
379 return self.unop_table[operator](arg)
380
381 def getitem(self, obj, argument):
382 """Subscribe an object from sandboxed code."""
383 try:
384 return obj[argument]
385 except (TypeError, LookupError):
386 if isinstance(argument, string_types):
387 try:
388 attr = str(argument)
389 except Exception:
390 pass
391 else:
392 try:
393 value = getattr(obj, attr)
394 except AttributeError:
395 pass
396 else:
397 if self.is_safe_attribute(obj, argument, value):
398 return value
399 return self.unsafe_undefined(obj, argument)
400 return self.undefined(obj=obj, name=argument)
401
402 def getattr(self, obj, attribute):
403 """Subscribe an object from sandboxed code and prefer the
404 attribute. The attribute passed *must* be a bytestring.
405 """
406 try:
407 value = getattr(obj, attribute)
408 except AttributeError:
409 try:
410 return obj[attribute]
411 except (TypeError, LookupError):
412 pass
413 else:
414 if self.is_safe_attribute(obj, attribute, value):
415 return value
416 return self.unsafe_undefined(obj, attribute)
417 return self.undefined(obj=obj, name=attribute)
418
419 def unsafe_undefined(self, obj, attribute):
420 """Return an undefined object for unsafe attributes."""
421 return self.undefined(
422 "access to attribute %r of %r "
423 "object is unsafe." % (attribute, obj.__class__.__name__),
424 name=attribute,
425 obj=obj,
426 exc=SecurityError,
427 )
428
429 def format_string(self, s, args, kwargs, format_func=None):
430 """If a format call is detected, then this is routed through this
431 method so that our safety sandbox can be used for it.
432 """
433 if isinstance(s, Markup):
434 formatter = SandboxedEscapeFormatter(self, s.escape)
435 else:
436 formatter = SandboxedFormatter(self)
437
438 if format_func is not None and format_func.__name__ == "format_map":
439 if len(args) != 1 or kwargs:
440 raise TypeError(
441 "format_map() takes exactly one argument %d given"
442 % (len(args) + (kwargs is not None))
443 )
444
445 kwargs = args[0]
446 args = None
447
448 kwargs = _MagicFormatMapping(args, kwargs)
449 rv = formatter.vformat(s, args, kwargs)
450 return type(s)(rv)
451
452 def call(__self, __context, __obj, *args, **kwargs): # noqa: B902
453 """Call an object from sandboxed code."""
454 fmt = inspect_format_method(__obj)
455 if fmt is not None:
456 return __self.format_string(fmt, args, kwargs, __obj)
457
458 # the double prefixes are to avoid double keyword argument
459 # errors when proxying the call.
460 if not __self.is_safe_callable(__obj):
461 raise SecurityError("%r is not safely callable" % (__obj,))
462 return __context.call(__obj, *args, **kwargs)
463
464
465 class ImmutableSandboxedEnvironment(SandboxedEnvironment):
466 """Works exactly like the regular `SandboxedEnvironment` but does not
467 permit modifications on the builtin mutable objects `list`, `set`, and
468 `dict` by using the :func:`modifies_known_mutable` function.
469 """
470
471 def is_safe_attribute(self, obj, attr, value):
472 if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value):
473 return False
474 return not modifies_known_mutable(obj, attr)
475
476
477 # This really is not a public API apparently.
478 try:
479 from _string import formatter_field_name_split
480 except ImportError:
481
482 def formatter_field_name_split(field_name):
483 return field_name._formatter_field_name_split()
484
485
486 class SandboxedFormatterMixin(object):
487 def __init__(self, env):
488 self._env = env
489
490 def get_field(self, field_name, args, kwargs):
491 first, rest = formatter_field_name_split(field_name)
492 obj = self.get_value(first, args, kwargs)
493 for is_attr, i in rest:
494 if is_attr:
495 obj = self._env.getattr(obj, i)
496 else:
497 obj = self._env.getitem(obj, i)
498 return obj, first
499
500
501 class SandboxedFormatter(SandboxedFormatterMixin, Formatter):
502 def __init__(self, env):
503 SandboxedFormatterMixin.__init__(self, env)
504 Formatter.__init__(self)
505
506
507 class SandboxedEscapeFormatter(SandboxedFormatterMixin, EscapeFormatter):
508 def __init__(self, env, escape):
509 SandboxedFormatterMixin.__init__(self, env)
510 EscapeFormatter.__init__(self, escape)