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""" 15import operator 16from jinja2.runtime import Undefined 17from jinja2.environment import Environment 18from jinja2.exceptions import SecurityError 19from jinja2.utils import FunctionType, MethodType, TracebackType, CodeType, \ 20 FrameType, GeneratorType 21 22 23#: maximum number of items a range may produce 24MAX_RANGE = 100000 25 26#: attributes of function objects that are considered unsafe. 27UNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict', 28 'func_defaults', 'func_globals']) 29 30#: unsafe method attributes. function attributes are unsafe for methods too 31UNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self']) 32 33 34import warnings 35 36# make sure we don't warn in python 2.6 about stuff we don't care about 37warnings.filterwarnings('ignore', 'the sets module', DeprecationWarning, 38 module='jinja2.sandbox') 39 40from collections import deque 41 42_mutable_set_types = (set,) 43_mutable_mapping_types = (dict,) 44_mutable_sequence_types = (list,) 45 46 47# on python 2.x we can register the user collection types 48try: 49 from UserDict import UserDict, DictMixin 50 from UserList import UserList 51 _mutable_mapping_types += (UserDict, DictMixin) 52 _mutable_set_types += (UserList,) 53except ImportError: 54 pass 55 56# if sets is still available, register the mutable set from there as well 57try: 58 from sets import Set 59 _mutable_set_types += (Set,) 60except ImportError: 61 pass 62 63#: register Python 2.6 abstract base classes 64try: 65 from collections import MutableSet, MutableMapping, MutableSequence 66 _mutable_set_types += (MutableSet,) 67 _mutable_mapping_types += (MutableMapping,) 68 _mutable_sequence_types += (MutableSequence,) 69except ImportError: 70 pass 71 72_mutable_spec = ( 73 (_mutable_set_types, frozenset([ 74 'add', 'clear', 'difference_update', 'discard', 'pop', 'remove', 75 'symmetric_difference_update', 'update' 76 ])), 77 (_mutable_mapping_types, frozenset([ 78 'clear', 'pop', 'popitem', 'setdefault', 'update' 79 ])), 80 (_mutable_sequence_types, frozenset([ 81 'append', 'reverse', 'insert', 'sort', 'extend', 'remove' 82 ])), 83 (deque, frozenset([ 84 'append', 'appendleft', 'clear', 'extend', 'extendleft', 'pop', 85 'popleft', 'remove', 'rotate' 86 ])) 87) 88 89 90def safe_range(*args): 91 """A range that can't generate ranges with a length of more than 92 MAX_RANGE items. 93 """ 94 rng = xrange(*args) 95 if len(rng) > MAX_RANGE: 96 raise OverflowError('range too big, maximum size for range is %d' % 97 MAX_RANGE) 98 return rng 99 100 101def unsafe(f): 102 """ 103 Mark a function or method as unsafe:: 104 105 @unsafe 106 def delete(self): 107 pass 108 """ 109 f.unsafe_callable = True 110 return f 111 112 113def 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 145def 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 173class 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 def __init__(self, *args, **kwargs): 186 Environment.__init__(self, *args, **kwargs) 187 self.globals['range'] = safe_range 188 189 def is_safe_attribute(self, obj, attr, value): 190 """The sandboxed environment will call this method to check if the 191 attribute of an object is safe to access. Per default all attributes 192 starting with an underscore are considered private as well as the 193 special attributes of internal python objects as returned by the 194 :func:`is_internal_attribute` function. 195 """ 196 return not (attr.startswith('_') or is_internal_attribute(obj, attr)) 197 198 def is_safe_callable(self, obj): 199 """Check if an object is safely callable. Per default a function is 200 considered safe unless the `unsafe_callable` attribute exists and is 201 True. Override this method to alter the behavior, but this won't 202 affect the `unsafe` decorator from this module. 203 """ 204 return not (getattr(obj, 'unsafe_callable', False) or \ 205 getattr(obj, 'alters_data', False)) 206 207 def getitem(self, obj, argument): 208 """Subscribe an object from sandboxed code.""" 209 try: 210 return obj[argument] 211 except (TypeError, LookupError): 212 if isinstance(argument, basestring): 213 try: 214 attr = str(argument) 215 except: 216 pass 217 else: 218 try: 219 value = getattr(obj, attr) 220 except AttributeError: 221 pass 222 else: 223 if self.is_safe_attribute(obj, argument, value): 224 return value 225 return self.unsafe_undefined(obj, argument) 226 return self.undefined(obj=obj, name=argument) 227 228 def getattr(self, obj, attribute): 229 """Subscribe an object from sandboxed code and prefer the 230 attribute. The attribute passed *must* be a bytestring. 231 """ 232 try: 233 value = getattr(obj, attribute) 234 except AttributeError: 235 try: 236 return obj[attribute] 237 except (TypeError, LookupError): 238 pass 239 else: 240 if self.is_safe_attribute(obj, attribute, value): 241 return value 242 return self.unsafe_undefined(obj, attribute) 243 return self.undefined(obj=obj, name=attribute) 244 245 def unsafe_undefined(self, obj, attribute): 246 """Return an undefined object for unsafe attributes.""" 247 return self.undefined('access to attribute %r of %r ' 248 'object is unsafe.' % ( 249 attribute, 250 obj.__class__.__name__ 251 ), name=attribute, obj=obj, exc=SecurityError) 252 253 def call(__self, __context, __obj, *args, **kwargs): 254 """Call an object from sandboxed code.""" 255 # the double prefixes are to avoid double keyword argument 256 # errors when proxying the call. 257 if not __self.is_safe_callable(__obj): 258 raise SecurityError('%r is not safely callable' % (__obj,)) 259 return __context.call(__obj, *args, **kwargs) 260 261 262class ImmutableSandboxedEnvironment(SandboxedEnvironment): 263 """Works exactly like the regular `SandboxedEnvironment` but does not 264 permit modifications on the builtin mutable objects `list`, `set`, and 265 `dict` by using the :func:`modifies_known_mutable` function. 266 """ 267 268 def is_safe_attribute(self, obj, attr, value): 269 if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value): 270 return False 271 return not modifies_known_mutable(obj, attr) 272