1# -*- coding: utf-8 -*- 2"""A sandbox layer that ensures unsafe operations cannot be performed. 3Useful when the template itself comes from an untrusted source. 4""" 5import operator 6import types 7import warnings 8from collections import deque 9from string import Formatter 10 11from markupsafe import EscapeFormatter 12from markupsafe import Markup 13 14from ._compat import abc 15from ._compat import PY2 16from ._compat import range_type 17from ._compat import string_types 18from .environment import Environment 19from .exceptions import SecurityError 20 21#: maximum number of items a range may produce 22MAX_RANGE = 100000 23 24#: attributes of function objects that are considered unsafe. 25if PY2: 26 UNSAFE_FUNCTION_ATTRIBUTES = { 27 "func_closure", 28 "func_code", 29 "func_dict", 30 "func_defaults", 31 "func_globals", 32 } 33else: 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 39UNSAFE_METHOD_ATTRIBUTES = {"im_class", "im_func", "im_self"} 40 41#: unsafe generator attributes. 42UNSAFE_GENERATOR_ATTRIBUTES = {"gi_frame", "gi_code"} 43 44#: unsafe attributes on coroutines 45UNSAFE_COROUTINE_ATTRIBUTES = {"cr_frame", "cr_code"} 46 47#: unsafe attributes on async generators 48UNSAFE_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 51warnings.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 60try: 61 from UserDict import UserDict, DictMixin 62 from UserList import UserList 63 64 _mutable_mapping_types += (UserDict, DictMixin) 65 _mutable_set_types += (UserList,) 66except ImportError: 67 pass 68 69# if sets is still available, register the mutable set from there as well 70try: 71 from sets import Set 72 73 _mutable_set_types += (Set,) 74except 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 125class _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 156def 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 166def 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 181def 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 194def 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 231def 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 259class 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 465class 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. 478try: 479 from _string import formatter_field_name_split 480except ImportError: 481 482 def formatter_field_name_split(field_name): 483 return field_name._formatter_field_name_split() 484 485 486class 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 501class SandboxedFormatter(SandboxedFormatterMixin, Formatter): 502 def __init__(self, env): 503 SandboxedFormatterMixin.__init__(self, env) 504 Formatter.__init__(self) 505 506 507class SandboxedEscapeFormatter(SandboxedFormatterMixin, EscapeFormatter): 508 def __init__(self, env, escape): 509 SandboxedFormatterMixin.__init__(self, env) 510 EscapeFormatter.__init__(self, escape) 511