blob: 714a0e1a11364f6230f3badcc4b548ad6604c956 [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
12 :copyright: Copyright 2008 by Armin Ronacher.
13 :license: BSD.
14"""
Armin Ronacherb5f522c2008-05-04 18:25:02 +020015from types import FunctionType, MethodType, TracebackType, CodeType, \
16 FrameType, GeneratorType
Armin Ronacherc63243e2008-04-14 22:53:58 +020017from jinja2.runtime import Undefined
18from jinja2.environment import Environment
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +020019from jinja2.exceptions import SecurityError
Armin Ronacherc63243e2008-04-14 22:53:58 +020020
21
22#: maximum number of items a range may produce
23MAX_RANGE = 100000
24
Armin Ronacher76c280b2008-05-04 12:31:48 +020025#: attributes of function objects that are considered unsafe.
26UNSAFE_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
30UNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self'])
31
Armin Ronacherc63243e2008-04-14 22:53:58 +020032
33def safe_range(*args):
34 """A range that can't generate ranges with a length of more than
Armin Ronacher7ceced52008-05-03 10:15:31 +020035 MAX_RANGE items.
36 """
Armin Ronacherc63243e2008-04-14 22:53:58 +020037 rng = xrange(*args)
38 if len(rng) > MAX_RANGE:
Armin Ronacher76c280b2008-05-04 12:31:48 +020039 raise OverflowError('range too big, maximum size for range is %d' %
40 MAX_RANGE)
Armin Ronacherc63243e2008-04-14 22:53:58 +020041 return rng
42
43
44def unsafe(f):
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +020045 """
46 Mark a function or method as unsafe::
47
48 @unsafe
49 def delete(self):
50 pass
51 """
Armin Ronacherc63243e2008-04-14 22:53:58 +020052 f.unsafe_callable = True
53 return f
54
55
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +020056def is_internal_attribute(obj, attr):
57 """Test if the attribute given is an internal python attribute. For
58 example this function returns `True` for the `func_code` attribute of
59 python objects. This is useful if the environment method
60 :meth:`~SandboxedEnvironment.is_safe_attribute` is overriden.
61
62 >>> from jinja2.sandbox import is_internal_attribute
63 >>> is_internal_attribute(lambda: None, "func_code")
64 True
65 >>> is_internal_attribute((lambda x:x).func_code, 'co_code')
66 True
67 >>> is_internal_attribute(str, "upper")
68 False
69 """
70 if isinstance(obj, FunctionType):
71 return attr in UNSAFE_FUNCTION_ATTRIBUTES
72 if isinstance(obj, MethodType):
73 return attr in UNSAFE_FUNCTION_ATTRIBUTES or \
74 attr in UNSAFE_METHOD_ATTRIBUTES
75 if isinstance(obj, type):
76 return attr == 'mro'
77 if isinstance(obj, (CodeType, TracebackType, FrameType)):
78 return True
79 if isinstance(obj, GeneratorType):
80 return attr == 'gi_frame'
81 return attr.startswith('__')
82
83
Armin Ronacherc63243e2008-04-14 22:53:58 +020084class SandboxedEnvironment(Environment):
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +020085 """The sandboxed environment. It works like the regular environment but
86 tells the compiler to generate sandboxed code. Additionally subclasses of
87 this environment may override the methods that tell the runtime what
88 attributes or functions are safe to access.
89
90 If the template tries to access insecure code a :exc:`SecurityError` is
91 raised. However also other exceptions may occour during the rendering so
92 the caller has to ensure that all exceptions are catched.
93 """
Armin Ronacherc63243e2008-04-14 22:53:58 +020094 sandboxed = True
95
96 def __init__(self, *args, **kwargs):
97 Environment.__init__(self, *args, **kwargs)
98 self.globals['range'] = safe_range
99
Armin Ronacher9a822052008-04-17 18:44:07 +0200100 def is_safe_attribute(self, obj, attr, value):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200101 """The sandboxed environment will call this method to check if the
102 attribute of an object is safe to access. Per default all attributes
103 starting with an underscore are considered private as well as the
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200104 special attributes of internal python objects as returned by the
105 :func:`is_internal_attribute` function.
Armin Ronacherc63243e2008-04-14 22:53:58 +0200106 """
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200107 return not (attr.startswith('_') or is_internal_attribute(obj, attr))
Armin Ronacherc63243e2008-04-14 22:53:58 +0200108
109 def is_safe_callable(self, obj):
110 """Check if an object is safely callable. Per default a function is
111 considered safe unless the `unsafe_callable` attribute exists and is
Armin Ronacher7ceced52008-05-03 10:15:31 +0200112 True. Override this method to alter the behavior, but this won't
Armin Ronacherc63243e2008-04-14 22:53:58 +0200113 affect the `unsafe` decorator from this module.
114 """
Armin Ronacher7ceced52008-05-03 10:15:31 +0200115 return not (getattr(obj, 'unsafe_callable', False) or \
116 getattr(obj, 'alters_data', False))
Armin Ronacherc63243e2008-04-14 22:53:58 +0200117
Armin Ronacher9a822052008-04-17 18:44:07 +0200118 def subscribe(self, obj, argument):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200119 """Subscribe an object from sandboxed code."""
Armin Ronacher9a822052008-04-17 18:44:07 +0200120 is_unsafe = False
Armin Ronacher08a6a3b2008-05-13 15:35:47 +0200121 if isinstance(argument, basestring):
122 try:
Armin Ronacherab5ad8c2008-05-17 00:34:11 +0200123 attr = str(argument)
124 except:
Armin Ronacher08a6a3b2008-05-13 15:35:47 +0200125 pass
126 else:
Armin Ronacherab5ad8c2008-05-17 00:34:11 +0200127 try:
128 value = getattr(obj, attr)
129 except AttributeError:
130 pass
131 else:
132 if self.is_safe_attribute(obj, argument, value):
133 return value
134 is_unsafe = True
Armin Ronacher9a822052008-04-17 18:44:07 +0200135 try:
136 return obj[argument]
Armin Ronacherc63243e2008-04-14 22:53:58 +0200137 except (TypeError, LookupError):
Armin Ronacher9a822052008-04-17 18:44:07 +0200138 if is_unsafe:
139 return self.undefined('access to attribute %r of %r object is'
140 ' unsafe.' % (
141 argument,
142 obj.__class__.__name__
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200143 ), name=argument, exc=SecurityError)
Armin Ronacher9a822052008-04-17 18:44:07 +0200144 return self.undefined(obj=obj, name=argument)
Armin Ronacherc63243e2008-04-14 22:53:58 +0200145
146 def call(__self, __obj, *args, **kwargs):
147 """Call an object from sandboxed code."""
148 # the double prefixes are to avoid double keyword argument
149 # errors when proxying the call.
150 if not __self.is_safe_callable(__obj):
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200151 raise SecurityError('%r is not safely callable' % (__obj,))
Armin Ronacherc63243e2008-04-14 22:53:58 +0200152 return __obj(*args, **kwargs)