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) 2010 by the Jinja Team. 13 :license: BSD. 14 """ 15 import operator 16 from jinja2.environment import Environment 17 from jinja2.exceptions import SecurityError 18 from jinja2.utils import FunctionType, MethodType, TracebackType, CodeType, \ 19 FrameType, GeneratorType 20 21 22 #: maximum number of items a range may produce 23 MAX_RANGE = 100000 24 25 #: attributes of function objects that are considered unsafe. 26 UNSAFE_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 30 UNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self']) 31 32 33 import warnings 34 35 # make sure we don't warn in python 2.6 about stuff we don't care about 36 warnings.filterwarnings('ignore', 'the sets module', DeprecationWarning, 37 module='jinja2.sandbox') 38 39 from collections import deque 40 41 _mutable_set_types = (set,) 42 _mutable_mapping_types = (dict,) 43 _mutable_sequence_types = (list,) 44 45 46 # on python 2.x we can register the user collection types 47 try: 48 from UserDict import UserDict, DictMixin 49 from UserList import UserList 50 _mutable_mapping_types += (UserDict, DictMixin) 51 _mutable_set_types += (UserList,) 52 except ImportError: 53 pass 54 55 # if sets is still available, register the mutable set from there as well 56 try: 57 from sets import Set 58 _mutable_set_types += (Set,) 59 except ImportError: 60 pass 61 62 #: register Python 2.6 abstract base classes 63 try: 64 from collections import MutableSet, MutableMapping, MutableSequence 65 _mutable_set_types += (MutableSet,) 66 _mutable_mapping_types += (MutableMapping,) 67 _mutable_sequence_types += (MutableSequence,) 68 except 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 ) 87 88 89 def safe_range(*args): 90 """A range that can't generate ranges with a length of more than 91 MAX_RANGE items. 92 """ 93 rng = xrange(*args) 94 if len(rng) > MAX_RANGE: 95 raise OverflowError('range too big, maximum size for range is %d' % 96 MAX_RANGE) 97 return rng 98 99 100 def unsafe(f): 101 """Marks a function or method as unsafe. 102 103 :: 104 105 @unsafe 106 def delete(self): 107 pass 108 """ 109 f.unsafe_callable = True 110 return f 111 112 113 def is_internal_attribute(obj, attr): 114 """Test if the attribute given is an internal python attribute. For 115 example this function returns `True` for the `func_code` attribute of 116 python objects. This is useful if the environment method 117 :meth:`~SandboxedEnvironment.is_safe_attribute` is overriden. 118 119 >>> from jinja2.sandbox import is_internal_attribute 120 >>> is_internal_attribute(lambda: None, "func_code") 121 True 122 >>> is_internal_attribute((lambda x:x).func_code, 'co_code') 123 True 124 >>> is_internal_attribute(str, "upper") 125 False 126 """ 127 if isinstance(obj, FunctionType): 128 if attr in UNSAFE_FUNCTION_ATTRIBUTES: 129 return True 130 elif isinstance(obj, MethodType): 131 if attr in UNSAFE_FUNCTION_ATTRIBUTES or \ 132 attr in UNSAFE_METHOD_ATTRIBUTES: 133 return True 134 elif isinstance(obj, type): 135 if attr == 'mro': 136 return True 137 elif isinstance(obj, (CodeType, TracebackType, FrameType)): 138 return True 139 elif isinstance(obj, GeneratorType): 140 if attr == 'gi_frame': 141 return True 142 return attr.startswith('__') 143 144 145 def modifies_known_mutable(obj, attr): 146 """This function checks if an attribute on a builtin mutable object 147 (list, dict, set or deque) would modify it if called. It also supports 148 the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and 149 with Python 2.6 onwards the abstract base classes `MutableSet`, 150 `MutableMapping`, and `MutableSequence`. 151 152 >>> modifies_known_mutable({}, "clear") 153 True 154 >>> modifies_known_mutable({}, "keys") 155 False 156 >>> modifies_known_mutable([], "append") 157 True 158 >>> modifies_known_mutable([], "index") 159 False 160 161 If called with an unsupported object (such as unicode) `False` is 162 returned. 163 164 >>> modifies_known_mutable("foo", "upper") 165 False 166 """ 167 for typespec, unsafe in _mutable_spec: 168 if isinstance(obj, typespec): 169 return attr in unsafe 170 return False 171 172 173 class SandboxedEnvironment(Environment): 174 """The sandboxed environment. It works like the regular environment but 175 tells the compiler to generate sandboxed code. Additionally subclasses of 176 this environment may override the methods that tell the runtime what 177 attributes or functions are safe to access. 178 179 If the template tries to access insecure code a :exc:`SecurityError` is 180 raised. However also other exceptions may occour during the rendering so 181 the caller has to ensure that all exceptions are catched. 182 """ 183 sandboxed = True 184 185 #: default callback table for the binary operators. A copy of this is 186 #: available on each instance of a sandboxed environment as 187 #: :attr:`binop_table` 188 default_binop_table = { 189 '+': operator.add, 190 '-': operator.sub, 191 '*': operator.mul, 192 '/': operator.truediv, 193 '//': operator.floordiv, 194 '**': operator.pow, 195 '%': operator.mod 196 } 197 198 #: default callback table for the unary operators. A copy of this is 199 #: available on each instance of a sandboxed environment as 200 #: :attr:`unop_table` 201 default_unop_table = { 202 '+': operator.pos, 203 '-': operator.neg 204 } 205 206 #: a set of binary operators that should be intercepted. Each operator 207 #: that is added to this set (empty by default) is delegated to the 208 #: :meth:`call_binop` method that will perform the operator. The default 209 #: operator callback is specified by :attr:`binop_table`. 210 #: 211 #: The following binary operators are interceptable: 212 #: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**`` 213 #: 214 #: The default operation form the operator table corresponds to the 215 #: builtin function. Intercepted calls are always slower than the native 216 #: operator call, so make sure only to intercept the ones you are 217 #: interested in. 218 #: 219 #: .. versionadded:: 2.6 220 intercepted_binops = frozenset() 221 222 #: a set of unary operators that should be intercepted. Each operator 223 #: that is added to this set (empty by default) is delegated to the 224 #: :meth:`call_unop` method that will perform the operator. The default 225 #: operator callback is specified by :attr:`unop_table`. 226 #: 227 #: The following unary operators are interceptable: ``+``, ``-`` 228 #: 229 #: The default operation form the operator table corresponds to the 230 #: builtin function. Intercepted calls are always slower than the native 231 #: operator call, so make sure only to intercept the ones you are 232 #: interested in. 233 #: 234 #: .. versionadded:: 2.6 235 intercepted_unops = frozenset() 236 237 def intercept_unop(self, operator): 238 """Called during template compilation with the name of a unary 239 operator to check if it should be intercepted at runtime. If this 240 method returns `True`, :meth:`call_unop` is excuted for this unary 241 operator. The default implementation of :meth:`call_unop` will use 242 the :attr:`unop_table` dictionary to perform the operator with the 243 same logic as the builtin one. 244 245 The following unary operators are interceptable: ``+`` and ``-`` 246 247 Intercepted calls are always slower than the native operator call, 248 so make sure only to intercept the ones you are interested in. 249 250 .. versionadded:: 2.6 251 """ 252 return False 253 254 255 def __init__(self, *args, **kwargs): 256 Environment.__init__(self, *args, **kwargs) 257 self.globals['range'] = safe_range 258 self.binop_table = self.default_binop_table.copy() 259 self.unop_table = self.default_unop_table.copy() 260 261 def is_safe_attribute(self, obj, attr, value): 262 """The sandboxed environment will call this method to check if the 263 attribute of an object is safe to access. Per default all attributes 264 starting with an underscore are considered private as well as the 265 special attributes of internal python objects as returned by the 266 :func:`is_internal_attribute` function. 267 """ 268 return not (attr.startswith('_') or is_internal_attribute(obj, attr)) 269 270 def is_safe_callable(self, obj): 271 """Check if an object is safely callable. Per default a function is 272 considered safe unless the `unsafe_callable` attribute exists and is 273 True. Override this method to alter the behavior, but this won't 274 affect the `unsafe` decorator from this module. 275 """ 276 return not (getattr(obj, 'unsafe_callable', False) or 277 getattr(obj, 'alters_data', False)) 278 279 def call_binop(self, context, operator, left, right): 280 """For intercepted binary operator calls (:meth:`intercepted_binops`) 281 this function is executed instead of the builtin operator. This can 282 be used to fine tune the behavior of certain operators. 283 284 .. versionadded:: 2.6 285 """ 286 return self.binop_table[operator](left, right) 287 288 def call_unop(self, context, operator, arg): 289 """For intercepted unary operator calls (:meth:`intercepted_unops`) 290 this function is executed instead of the builtin operator. This can 291 be used to fine tune the behavior of certain operators. 292 293 .. versionadded:: 2.6 294 """ 295 return self.unop_table[operator](arg) 296 297 def getitem(self, obj, argument): 298 """Subscribe an object from sandboxed code.""" 299 try: 300 return obj[argument] 301 except (TypeError, LookupError): 302 if isinstance(argument, basestring): 303 try: 304 attr = str(argument) 305 except Exception: 306 pass 307 else: 308 try: 309 value = getattr(obj, attr) 310 except AttributeError: 311 pass 312 else: 313 if self.is_safe_attribute(obj, argument, value): 314 return value 315 return self.unsafe_undefined(obj, argument) 316 return self.undefined(obj=obj, name=argument) 317 318 def getattr(self, obj, attribute): 319 """Subscribe an object from sandboxed code and prefer the 320 attribute. The attribute passed *must* be a bytestring. 321 """ 322 try: 323 value = getattr(obj, attribute) 324 except AttributeError: 325 try: 326 return obj[attribute] 327 except (TypeError, LookupError): 328 pass 329 else: 330 if self.is_safe_attribute(obj, attribute, value): 331 return value 332 return self.unsafe_undefined(obj, attribute) 333 return self.undefined(obj=obj, name=attribute) 334 335 def unsafe_undefined(self, obj, attribute): 336 """Return an undefined object for unsafe attributes.""" 337 return self.undefined('access to attribute %r of %r ' 338 'object is unsafe.' % ( 339 attribute, 340 obj.__class__.__name__ 341 ), name=attribute, obj=obj, exc=SecurityError) 342 343 def call(__self, __context, __obj, *args, **kwargs): 344 """Call an object from sandboxed code.""" 345 # the double prefixes are to avoid double keyword argument 346 # errors when proxying the call. 347 if not __self.is_safe_callable(__obj): 348 raise SecurityError('%r is not safely callable' % (__obj,)) 349 return __context.call(__obj, *args, **kwargs) 350 351 352 class ImmutableSandboxedEnvironment(SandboxedEnvironment): 353 """Works exactly like the regular `SandboxedEnvironment` but does not 354 permit modifications on the builtin mutable objects `list`, `set`, and 355 `dict` by using the :func:`modifies_known_mutable` function. 356 """ 357 358 def is_safe_attribute(self, obj, attr, value): 359 if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value): 360 return False 361 return not modifies_known_mutable(obj, attr) 362