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