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