Mako templates and security - python

I have an idea to put the templates in the database, and offer the possibility for the designer to edit the templates direct from CMS panel. But what is haunted me is the security question. How could it be any secure if we have ability to put python commands directly in the templates. If I have something like this in a mako template:
<%!
import os
os.system('rm /var/www/env/harmless.txt')
%>
it will performed successful and harmless.txt will be removed. Should I find for another template engine except Mako or could I somehow configure Mako to prevent harmful code injection? On the other hand, some python commands incredibly helpful used in templates, inline if statement for example.

If they have their own separated instance of a CMS it doesn't matter like Loic points out. But if they are in some shared environment it is best to use another template engine. The question Untrusted templates in Python - what is a safe library to use? recommends Django templates and Jinja2.

There is still a possibility to do what you want. The mako engine lets you add a preprocessor to the template. I can't say for sure as I can test at the moment, but you could have something like this:
Here: http://docs.makotemplates.org/en/latest/usage.html#mako.template.Template.params.preprocessor
def removeImports(source):
# remove whatever you don't want inside the template
return new_source
tpl = Template(...., preprocessor=removeImports)
If you're using a framework like pyramid you can make it a new renderer to do that for you on all templates.
As a security concern, if you want to got that way as Mako is a terribly good engine in my own opinion. You should do a good set of test case on your preprocessor. I'm pretty sure that imports can be achieved inside inline python <% %>. Actually imports can be achieved almost anywhere inside the template as you can use inline python almost everywhere.
So if you're conerned about running python in a template, you can consider other templates such as Chameleon, Jinja2 ...

Related

Flask templates including incorrect files

I'm having a rather strange problem using a jinja2.ChoiceLoader (also tried with multiple paths with FileSystemLoader, no joy) in Flask.
I have several "theme" directories, like so.
/templates/
themes/
default/
layout.html
menu.html
blue/
layout.html
grey/
menu.html
...
And I'd like to fallback to default/ if the selected theme doesn't have the required template, so I used a ChoiceLoader, like so.
#app.before_request
def setup_request():
current_theme = get_theme()
logging.info('Using theme %s'%(current_theme))
app.jinja_loader = jinja2.ChoiceLoader([
jinja2.FileSystemLoader('/templates/themes/%s/'%(current_theme)),
jinja2.FileSystemLoader('/templates/themes/default/')
])
That's great, but if I change the <current_theme> it still loads the theme from the old folder until I reload Apache or restart the Flask development server.
It should be using the new theme. Logging says that it's using the changed theme, but apparently app.jinja_loader is a bit like honey badger... it's completely ignoring it until I reload Apache.
Edit: This appears to be related to Flask considering all files of the same name to be the same file. I can reproduce with the builtin server (with DEBUG=True), Cherry, and mod_wsgi. This person seems to have a similar problem, but no simple solution: flask blueprint template folder My situation is different in the sense that I require cascading templates for a single app. His problem is related to cascading templates between blueprints, but it may be the same issue under the hood.
Here's the code that's in the "get_theme()" call:
def get_theme():
# I know this is unsafe, testing only
return request.args.get('theme','default')
Edit 2: I need to change the HTML and JavaScript between themes, not just the CSS. This is why I'm not just loading different CSS files. Also, some of these themes are for mobile devices, and have very little in common with the other themes.
Edit 3: Two solutions. Solution 1: Name the files uniquely, like "blue.layout.html" and "default.layout.html". This works perfectly, but it doesn't cascade as required. Solution 2: Use relative paths, so instead of include 'file.html', use include 'theme/blue/file.html. I achieved cascading by creating a get_theme_file() function that checks for the active theme, checks if the file exists (if not, fallback to "default" theme), and returns the relative path. I just have to make sure everything I include looks like {% include get_theme_file('file.html') %}. This is not elegant, but I find it to be more elegant that the low-level fiddling with Flask used here.
By the way, you can pass multiple locations to FileSystemLoader, and it is the recommended way to load templates
This is expected behavior in Apache with mod_wsgi (which I assume you are using). File system changes don't trigger a reload of all the processes. See this entry in the Flask docs that talks about this, and offers a workaround which is to add:
WSGIScriptReloading On
To the configuration section for your application and then touching the wsgi file to trigger a reload of the child processes.
Are you sure this is what you intend? Most theme switching tricks rely on the cascading part of cascading style sheets (CSS) to control themes.
Well, I'm not the only one to encounter this problem. The issue is that Flask caches based on filename, and if you don't include the relative path it just caches the first one to be loaded. There are three ways to accomplish dynamic, cascading, templates.
Override Jinja builtins. Which I found to be quite confusing. I'm not smart enough for this solution.
Serve a different WSGI process for each file. The setup here seems a bit too much for a dynamic site. Flask caches the filenames per WSGI process, so you can do something with multiple Cherry WSGI servers, for example.
Include the theme in the load path. Create a function, load it in with context_processor, and only load template files using that function. The function needs to check for a non-default theme, check if the file exists, and return it. So a template call would be get_theme_file('layout.html') which would return the relative path (like themes/blue/layout.html).
An example of Option 3.
def get_theme_file(fname):
theme = get_theme()
if os.path.exists(os.path.join(theme.theme_dir, fname)):
return os.path.join('themes', theme.name, fname)
return os.path.join('themes', 'default', fname)
...
# Each render_template should reference this
return render_template(get_theme_file('layout.html'))
If you include theme files in templates:
{% include get_theme_file('layout.html') %}
Unfortunately, this doesn't cache, but I can see a few ways to optimize it. Maybe cache an os.listdir of the get_theme().theme_dir, and instead of reading the filesystem for each get_theme_file call, just do an in check against the cached listdir list.
It's worth noting that this is Flask specific. I was unable to reproduce this behavior with plain Jinja2 and my own WSGI server. One might say that Flask was a poor choice for this particular project, but I'd argue that the savings from everything else Flask does was well worth it.

Python template system like Smarty or Radius

Is there a Python template library similar to Smarty or Radius (Ruby's Movable Type-like template library) out there?
The python wiki entry on this topic is here: http://wiki.python.org/moin/Templating
The two well-known template systems other than Django are cheetah and jinja.
Django's templating system is not especially powerful, by design, because that discourages any logic other than pure presentation logic in the templates. This is something that I value, having used JSP and ASP.
Jinja is pretty much a superset of Django's templates, except that if you wanted you could embed all of your view code in it ( I wouldn't ).
Cheetah looks rather more like JSP.
Any of these can be used with Django (the full stack framework), or you could use one of the microframeworks or "bundled" frameworks. See this wiki page: http://wiki.python.org/moin/WebFrameworks
AFAIK, Django. It has an excellent templating system.
It's slightly different from PHP, because of the following:
Variables and methods must be passed in to the template renderer.
Variables and methods are noted by {{ braces }}.
Tags (Django's version of PHP flow control statements), are denoted like {% if x %}, followed by a loop termination (like {% endif %}.
You can call functions directly from the template, but they will not accept any arguments.
There's a lot more, but I would highly recommend that you read the Django book.
Just one note: from personal experience, Django's ORM isn't very good for legacy database integration, so if you're looking for that, you might want to try SQLalchemy.
EDIT: Marcin had a good summary - Django's templating system, by design, encourages the separation of presentation and processing logic (i.e., loose coupling).
EDIT 2: There's also mako, which has a more PHP-like syntax.

Is there a good way to apply pychecker/pylint to the python code in Tornado templates?

I am using Tornado 2.0 (Python 2.6.5) to build a simple web app.
Naturally, my Tornado templates contain snippets of Python code. For my non-template code, I am using pychecker and pylint to check for errors, etc.
However, obviously pychecker and pylint can't be run over the templates directly, b/c the templates are not python files proper (for non-Tornado users: they are html-like snippets w/ some control sequences and embedded python code).
So, my question is: can anyone suggest a good way to apply pychecker/pylint to the python code in these template files? Presumably this would involve extracting the code from the files.
I can hazard a few guesses as to how to do this, but I am curious if other people perceive this as a problem and what solutions they have pursued. I am still fairly new to web app design/construction so I am interested in answers guided by practical experience.
You need to use view class pattern to avoid cluttering your template with Python code which cannot be analyzed.
Create a Python class to process your view, instead of function
Have all "template logic" code as class methods. Your template calls them like {{ view.get_full_name }} and def get_full_name(self): return self.item.first_name + " " + self.item.last_name
Make instance out of your class
make call() as starting point for your processing
Pass "self" to your template as a context var
Some instructions for Django, but generally all Python frameworks (Pyramid, Zope) follow the same pattern:
Class views in Django
"$yourframeworkname view class" should yield more tutorials in Google.

Untrusted templates in Python - what is a safe library to use?

I am building a library that will be used in several Python applications. It get multilingual e-mail templates from an RMDBS, and then variable replacement will be performed on the template in Python before the e-mail is sent.
In addition to variable replacement, I need the template library to support if, elif, and for statements in the templates.
I use Mako for most my projects, and also looked at Tempita as it doesn't provide a lot of features I don't need.
The concern I have is untrusted code execution - can someone point me at a template solution for Python that either does not support code execution, or will allow me to disable it?
From the Django book:
For that reason, it’s impossible to call Python code directly within Django templates. All “programming” is fundamentally limited to the scope of what template tags can do. It is possible to write custom template tags that do arbitrary things, but the out-of-the-box Django template tags intentionally do not allow for arbitrary Python code execution.
Give Django templates a try. It's a little tricky to set up outside of a Django app -- something to do with DJANGO_SETTINGS_MODULE, search around -- but may be trusted.
Have you checked out Jinja2? It's pretty much what you're talking about, and it's a great mix of powerful while keeping things simple and not giving the designer too much power. :)
If you've used Django's template system, it's very similar (if not based off of?) Jinja.

How can I provide safety template for user to modify with python?

I am building a multi-user web application. Each user can have their own site under my application. I am considering how to allow user to modify template without security problem? I have evaluated some python template engine. For example, genshi, it is a pretty wonderful template engine, but however it might be dangerous to allow user to modify genshi template. It have a syntax like this:
<?python
?>
This syntax allow you run whatever you want python can do. I notice that it seems can be shutdown by passing some parameter. But there are still a lots of potential problems. For example, user can access build-in functions, and methods of passed variables. For example, if I pass a ORM object to template. It might contain some method and variable that I don't want to allow user touch it. May like this:
site.metadata.connection.execute("drop table xxx")
So my question is how can I allow user to modify template of their site without security problems? Any python template engine can be used.
Thanks.
Jinja2 is a Django-ish templating system that has a sandboxing feature. I've never attempted to use the sandboxing, but I quite like Jinja2 as an alternative to Django's templates. It still promotes separation of template from business logic, but has more Pythonic calling conventions, namespacing, etc.
Jinja2 Sandbox
Look at Django templte engine. It does not support execution of arbitrary python code and all accessible variables must be passed into template explicity. This should be pretty good foundation for building user-customizable pages. Beware that you'll still need to handle occasional syntax errors from your users.
In rails there's something called liquid. You might take a look at that to get some ideas. Another idea: at the very least, one thing you could do is to convert your objects into simple dictionary - something like a json representation, and then pass to your template.
The short answer is probably "you can't".
The best you can probably do is to trap the individual users in virtual machines or sandboxes.

Categories

Resources