blob: 98873102c855997fcb4c1e2fea0d0aa250096413 [file] [log] [blame]
Armin Ronacherc63243e2008-04-14 22:53:58 +02001# -*- 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
Armin Ronacher55494e42010-01-22 09:41:48 +010012 :copyright: (c) 2010 by the Jinja Team.
Armin Ronacherc63243e2008-04-14 22:53:58 +020013 :license: BSD.
14"""
Armin Ronacher522cad62008-05-17 13:55:37 +020015import operator
Armin Ronacherc63243e2008-04-14 22:53:58 +020016from jinja2.runtime import Undefined
17from jinja2.environment import Environment
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +020018from jinja2.exceptions import SecurityError
Armin Ronacher9a0078d2008-08-13 18:24:17 +020019from jinja2.utils import FunctionType, MethodType, TracebackType, CodeType, \
20 FrameType, GeneratorType
Armin Ronacherc63243e2008-04-14 22:53:58 +020021
22
23#: maximum number of items a range may produce
24MAX_RANGE = 100000
25
Armin Ronacher76c280b2008-05-04 12:31:48 +020026#: 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
Armin Ronacher522cad62008-05-17 13:55:37 +020033
Armin Ronacher51097172009-02-19 19:57:01 +010034import 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
40
Armin Ronacherd71fff02008-05-26 23:57:07 +020041from collections import deque
Armin Ronacherd71fff02008-05-26 23:57:07 +020042from UserDict import UserDict, DictMixin
43from UserList import UserList
Armin Ronacher51097172009-02-19 19:57:01 +010044_mutable_set_types = (set,)
Armin Ronacherd71fff02008-05-26 23:57:07 +020045_mutable_mapping_types = (UserDict, DictMixin, dict)
46_mutable_sequence_types = (UserList, list)
Armin Ronacher522cad62008-05-17 13:55:37 +020047
Armin Ronacher51097172009-02-19 19:57:01 +010048# if sets is still available, register the mutable set from there as well
49try:
50 from sets import Set
51 _mutable_set_types += (Set,)
52except ImportError:
53 pass
54
Armin Ronacherd71fff02008-05-26 23:57:07 +020055#: register Python 2.6 abstract base classes
56try:
57 from collections import MutableSet, MutableMapping, MutableSequence
58 _mutable_set_types += (MutableSet,)
59 _mutable_mapping_types += (MutableMapping,)
60 _mutable_sequence_types += (MutableSequence,)
61except ImportError:
62 pass
63
64_mutable_spec = (
65 (_mutable_set_types, frozenset([
66 'add', 'clear', 'difference_update', 'discard', 'pop', 'remove',
67 'symmetric_difference_update', 'update'
68 ])),
69 (_mutable_mapping_types, frozenset([
70 'clear', 'pop', 'popitem', 'setdefault', 'update'
71 ])),
72 (_mutable_sequence_types, frozenset([
73 'append', 'reverse', 'insert', 'sort', 'extend', 'remove'
74 ])),
75 (deque, frozenset([
76 'append', 'appendleft', 'clear', 'extend', 'extendleft', 'pop',
77 'popleft', 'remove', 'rotate'
78 ]))
79)
Armin Ronacher522cad62008-05-17 13:55:37 +020080
Armin Ronacherc63243e2008-04-14 22:53:58 +020081
82def safe_range(*args):
83 """A range that can't generate ranges with a length of more than
Armin Ronacher7ceced52008-05-03 10:15:31 +020084 MAX_RANGE items.
85 """
Armin Ronacherc63243e2008-04-14 22:53:58 +020086 rng = xrange(*args)
87 if len(rng) > MAX_RANGE:
Armin Ronacher76c280b2008-05-04 12:31:48 +020088 raise OverflowError('range too big, maximum size for range is %d' %
89 MAX_RANGE)
Armin Ronacherc63243e2008-04-14 22:53:58 +020090 return rng
91
92
93def unsafe(f):
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +020094 """
95 Mark a function or method as unsafe::
96
97 @unsafe
98 def delete(self):
99 pass
100 """
Armin Ronacherc63243e2008-04-14 22:53:58 +0200101 f.unsafe_callable = True
102 return f
103
104
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200105def is_internal_attribute(obj, attr):
106 """Test if the attribute given is an internal python attribute. For
107 example this function returns `True` for the `func_code` attribute of
108 python objects. This is useful if the environment method
109 :meth:`~SandboxedEnvironment.is_safe_attribute` is overriden.
110
111 >>> from jinja2.sandbox import is_internal_attribute
112 >>> is_internal_attribute(lambda: None, "func_code")
113 True
114 >>> is_internal_attribute((lambda x:x).func_code, 'co_code')
115 True
116 >>> is_internal_attribute(str, "upper")
117 False
118 """
119 if isinstance(obj, FunctionType):
Armin Ronacherd71fff02008-05-26 23:57:07 +0200120 if attr in UNSAFE_FUNCTION_ATTRIBUTES:
121 return True
122 elif isinstance(obj, MethodType):
123 if attr in UNSAFE_FUNCTION_ATTRIBUTES or \
124 attr in UNSAFE_METHOD_ATTRIBUTES:
125 return True
126 elif isinstance(obj, type):
127 if attr == 'mro':
128 return True
129 elif isinstance(obj, (CodeType, TracebackType, FrameType)):
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200130 return True
Armin Ronacherd71fff02008-05-26 23:57:07 +0200131 elif isinstance(obj, GeneratorType):
132 if attr == 'gi_frame':
133 return True
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200134 return attr.startswith('__')
135
136
Armin Ronacherd71fff02008-05-26 23:57:07 +0200137def modifies_known_mutable(obj, attr):
Armin Ronacher522cad62008-05-17 13:55:37 +0200138 """This function checks if an attribute on a builtin mutable object
Armin Ronacherd71fff02008-05-26 23:57:07 +0200139 (list, dict, set or deque) would modify it if called. It also supports
140 the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and
141 with Python 2.6 onwards the abstract base classes `MutableSet`,
142 `MutableMapping`, and `MutableSequence`.
Armin Ronacher522cad62008-05-17 13:55:37 +0200143
Armin Ronacherd71fff02008-05-26 23:57:07 +0200144 >>> modifies_known_mutable({}, "clear")
Armin Ronacher522cad62008-05-17 13:55:37 +0200145 True
Armin Ronacherd71fff02008-05-26 23:57:07 +0200146 >>> modifies_known_mutable({}, "keys")
Armin Ronacher522cad62008-05-17 13:55:37 +0200147 False
Armin Ronacherd71fff02008-05-26 23:57:07 +0200148 >>> modifies_known_mutable([], "append")
Armin Ronacher522cad62008-05-17 13:55:37 +0200149 True
Armin Ronacherd71fff02008-05-26 23:57:07 +0200150 >>> modifies_known_mutable([], "index")
Armin Ronacher522cad62008-05-17 13:55:37 +0200151 False
152
153 If called with an unsupported object (such as unicode) `False` is
154 returned.
155
Armin Ronacherd71fff02008-05-26 23:57:07 +0200156 >>> modifies_known_mutable("foo", "upper")
Armin Ronacher522cad62008-05-17 13:55:37 +0200157 False
158 """
Armin Ronacherd71fff02008-05-26 23:57:07 +0200159 for typespec, unsafe in _mutable_spec:
160 if isinstance(obj, typespec):
161 return attr in unsafe
Armin Ronacher522cad62008-05-17 13:55:37 +0200162 return False
163
164
Armin Ronacherc63243e2008-04-14 22:53:58 +0200165class SandboxedEnvironment(Environment):
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200166 """The sandboxed environment. It works like the regular environment but
167 tells the compiler to generate sandboxed code. Additionally subclasses of
168 this environment may override the methods that tell the runtime what
169 attributes or functions are safe to access.
170
171 If the template tries to access insecure code a :exc:`SecurityError` is
172 raised. However also other exceptions may occour during the rendering so
173 the caller has to ensure that all exceptions are catched.
174 """
Armin Ronacherc63243e2008-04-14 22:53:58 +0200175 sandboxed = True
176
177 def __init__(self, *args, **kwargs):
178 Environment.__init__(self, *args, **kwargs)
179 self.globals['range'] = safe_range
180
Armin Ronacher9a822052008-04-17 18:44:07 +0200181 def is_safe_attribute(self, obj, attr, value):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200182 """The sandboxed environment will call this method to check if the
183 attribute of an object is safe to access. Per default all attributes
184 starting with an underscore are considered private as well as the
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200185 special attributes of internal python objects as returned by the
186 :func:`is_internal_attribute` function.
Armin Ronacherc63243e2008-04-14 22:53:58 +0200187 """
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200188 return not (attr.startswith('_') or is_internal_attribute(obj, attr))
Armin Ronacherc63243e2008-04-14 22:53:58 +0200189
190 def is_safe_callable(self, obj):
191 """Check if an object is safely callable. Per default a function is
192 considered safe unless the `unsafe_callable` attribute exists and is
Armin Ronacher7ceced52008-05-03 10:15:31 +0200193 True. Override this method to alter the behavior, but this won't
Armin Ronacherc63243e2008-04-14 22:53:58 +0200194 affect the `unsafe` decorator from this module.
195 """
Armin Ronacher7ceced52008-05-03 10:15:31 +0200196 return not (getattr(obj, 'unsafe_callable', False) or \
197 getattr(obj, 'alters_data', False))
Armin Ronacherc63243e2008-04-14 22:53:58 +0200198
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200199 def getitem(self, obj, argument):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200200 """Subscribe an object from sandboxed code."""
Armin Ronacher9a822052008-04-17 18:44:07 +0200201 try:
202 return obj[argument]
Armin Ronacherc63243e2008-04-14 22:53:58 +0200203 except (TypeError, LookupError):
Armin Ronacherf15f5f72008-05-26 12:21:45 +0200204 if isinstance(argument, basestring):
205 try:
206 attr = str(argument)
207 except:
208 pass
209 else:
210 try:
211 value = getattr(obj, attr)
212 except AttributeError:
213 pass
214 else:
215 if self.is_safe_attribute(obj, argument, value):
216 return value
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200217 return self.unsafe_undefined(obj, argument)
Armin Ronacher9a822052008-04-17 18:44:07 +0200218 return self.undefined(obj=obj, name=argument)
Armin Ronacherc63243e2008-04-14 22:53:58 +0200219
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200220 def getattr(self, obj, attribute):
221 """Subscribe an object from sandboxed code and prefer the
222 attribute. The attribute passed *must* be a bytestring.
223 """
224 try:
225 value = getattr(obj, attribute)
226 except AttributeError:
227 try:
Armin Ronacher9efe0812008-11-02 12:22:00 +0100228 return obj[attribute]
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200229 except (TypeError, LookupError):
230 pass
231 else:
232 if self.is_safe_attribute(obj, attribute, value):
233 return value
234 return self.unsafe_undefined(obj, attribute)
Armin Ronacher9efe0812008-11-02 12:22:00 +0100235 return self.undefined(obj=obj, name=attribute)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200236
237 def unsafe_undefined(self, obj, attribute):
238 """Return an undefined object for unsafe attributes."""
239 return self.undefined('access to attribute %r of %r '
240 'object is unsafe.' % (
241 attribute,
242 obj.__class__.__name__
243 ), name=attribute, obj=obj, exc=SecurityError)
244
Armin Ronacherfd310492008-05-25 00:16:51 +0200245 def call(__self, __context, __obj, *args, **kwargs):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200246 """Call an object from sandboxed code."""
247 # the double prefixes are to avoid double keyword argument
248 # errors when proxying the call.
249 if not __self.is_safe_callable(__obj):
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200250 raise SecurityError('%r is not safely callable' % (__obj,))
Armin Ronacherfd310492008-05-25 00:16:51 +0200251 return __context.call(__obj, *args, **kwargs)
Armin Ronacher522cad62008-05-17 13:55:37 +0200252
253
254class ImmutableSandboxedEnvironment(SandboxedEnvironment):
255 """Works exactly like the regular `SandboxedEnvironment` but does not
256 permit modifications on the builtin mutable objects `list`, `set`, and
Armin Ronacherd71fff02008-05-26 23:57:07 +0200257 `dict` by using the :func:`modifies_known_mutable` function.
Armin Ronacher522cad62008-05-17 13:55:37 +0200258 """
259
260 def is_safe_attribute(self, obj, attr, value):
261 if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value):
262 return False
Armin Ronacherd71fff02008-05-26 23:57:07 +0200263 return not modifies_known_mutable(obj, attr)