This is an update to THIS question as V3 is now available since some time:
I am also thinking about using RazorEngine
for mail-templates (and possibly even more).
Is there now a "sufficient secure mode" available to let users define templates?
With the IsolatedTemplateService
I can avoid users beeing able to access my domain objects, but what about the other stuff also discussed in the old question like editing/deleting files?
Also whats about accessing the DB "manually" (by reading the connection-string from config file if file access is possible or in the worst case simple bruteforce) and e.g. add a user as an admin?
Is there a way to "disable" all this stuff for the custom AppDomain
created by/for the IsolatedTemplateService
?
I was able to solve this by NOT using RazorEngine
, but make my own implementation (based on some code frome there).
The main problem with RazorEngine
is the following:
For the CodeDomProvider
needed to compile the razor template you need a "Full Trust" AppDomain
, but the IsolatedTemplateService
does execute "everything" in the new AppDomain
so it fails compiling the template.
I solved this by splitting this up into two parts:
Step one I do in the "main AppDomain
" and only step 2 in the "restricted AppDomain
".
There was then one additional problem:
If you compile the template "in memory" (=> without generating a *.dll
file), which is done by RazorEngine
, it is directly loaded in the current AppDomain
which I did not want as it "inherits" that domains permissions then.
Because of this I disabled this and generate a *.dll
in a "common templates folder".
So after the compilation I have a *.dll
file containing the template which is not loaded anywhere yet.
The second AppDomain
is created with the following permission set:
PermissionSet permSet = new PermissionSet(PermissionState.None);
permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
permSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read, templatePath));
permSet.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess));
The first permission is needed to execute any code, the second is to allow the AppDomain
to load the generated assembly from my common templates folder and the third is for limited support for reflection (only in the loaded assembly, but not i.e. in System.*
) to support dynamic
so I can use a ViewBag
.
Every thing else is prohibited:
templatePath
I then call a Render
method in this restricted domain which loads the appropriate assembly and renders the template. This method also supports a timeout, after which the rendering is killed, to avoid while (true) ;
DOS attacks like suggested by Kris.
This seems to work fine so far. I did now release this as IsolatedRazor
including a NuGet package. May RazorEngine
can incorperate this as e.g. RestrictedIsolatedTemplateService
or so...