I am developing a commercial VB.net WPF application that needs user generated scripts for controlling the application to be shared between users. The best way that I have come across of accomplishing this so far without writing my own parser is using the Microsoft Script Control.
It would appear that both VBScripts and JScripts run through this control have access to wscript and as a result are too powerful to be shared between programmers and non-technical users for obvious security reasons.
I have considered trying to filter out dangerous scripts with some kind of regex parsing or something but that just seems far too risky and easy to circumvent.
So, is there some way of using this control but blocking its access to the system so that it could be used for controlling only the objects that I give it? If not, could someone recommend a better way of doing this?
I do not particularly mind what language the script would be in at this stage, although having multiple options would be nice.
EDIT: I am basing my conclusion that the control is too powerful for this on the fact that the following JScript code successfully launches notepad when called using the .AddCode and .Run methods of the control.
function test(){
var shell = new ActiveXObject("WScript.shell");
shell.run("notepad.exe", 1);
}
Thanks for all the help,
Sam.
If you just need to kill the ActiveXObject feature which is the entry point to the system, you can silently append some lines to the code you give to the Script Control, like this for example:
ActiveXObject = null; // add this silently
function test(){
var shell = new ActiveXObject("WScript.shell"); // this will now fail
shell.run("notepad.exe", 1);
}
Of course, if you still need to give some functions to your users, you will then need to propose some sort of an API, use the AddObject function (see How To Use the AddObject Method of the Script Control), and the user would use it like this:
ActiveXObject = null; // add this silently
function test(){
// this is a controlled method, because I have added a MyAPI named object
// using AddObject, and this object has a OpenNotepad method.
MyAPI.OpenNotepad();
}
PS: WScript is a, ActiveX Scripting host, so it's not accessible from the Script Control.
PS2: This hack does not work in every Script Control underlying languages. It works in JavaScript, but not in VBScript for example.
From your question, it doesn't look like you gave any consideration to any of the open-source script engines out there. I would suggest that those open-source libraries could solve your sandbox problem much more easily than the Microsoft Script Control.
The way I understand it, your requirements are:
Must be able to pass objects from your program into the scripting environment, so the script can use those objects to interact with the host app.
Must not be allowed to do unsafe things like access files, launch applications, create COM objects, etc.
Given those requirements, you have quite a few options.
The first thing that comes to mind is Jint, an open-source JavaScript interpreter written in .NET that you can embed in your app. You can pass .NET objects to the script. By default, the script can actually access any class in the .NET Framework, but the script is sandboxed by default (using .NET's built-in Code Access Security), so the script can't do anything unsafe. (For example, it could use things like StringBuilder or Regex, but it would get an exception if it tried to use FileStream.) If you want, you can disable the .NET access entirely, but even with it enabled, the default sandbox would probably suit your needs.
If for some reason Jint doesn't meet your requirements, some of the other open-source JavaScript-for-.NET engines I can think of off the top of my head are Jurassic, IronJS, and JavaScript .NET.
If it matters to you, Jint, Jurassic, and IronJS are all available through NuGet.
Related
How can I store, for example, the body of a method in a database and later run it? (I'm using Delphi XE2; maybe RTTI would help.)
RTTI is not a full language interpreter. Delphi is a compiled language. You write it, compile it, and distribute only your binaries. Unless you're Embarcadero, you don't have rights to distribute DCC32 (the command line compiler).
However, the JVCL includes a delphi-like language subset wrapped up in a very easy to use Component, called "JvInterpreter". You could write some code (as pascal) and place it in a database. You could then "run that code" (interpreted, not compiled) that you pull from the database. Typically these should be procedures that call methods in your code. YOu have to write some "wrappers" that expose the compiled APIs that you wish to expose to the interpreter (provide access to live data, or database connection objects, or table/query objects). You're thinking that this sounds perfect right? Well, it's a trap.
Beware of something called "the configuration complexity clock". YOu've just reached 9 o'clock, and that's where a lot of pain and suffering begins. Just like when you have a problem, and you solve it with regular expressions, and "now you have two problems", adding scripting and DSLs to your app has a way of solving one problem and creating several others.
While I think the "DLL stored in a database blob field" idea is evil, and absurd, I think that wanton addition of scripting and domain-specific languages to applications is also asking for a lot of pain. Ask yourself first if some other simpler solution could work. Then apply the YAGNI principle (You Ain't Gonna Need It) and KISS (keep-it-simple-smartguy).
Think twice before you implement anything like what you're asking about doing in your question.
Your best Option, IMHO, is using a scripting engine and storing scripts in the database.
Alternatively you could put the code in a dll and put that dll in the database. There is code for loading a dll from a resource into ram and processing it so it can be used as if it was loaded using LoadLibrary, e.g. in dzlib. I don't really know whether works with any dll and in which versions of Windows, but it does with the ones I tried.
I have quite a deal of experience programing with VB6, VB.NET, C# so on and have used ADO, then SubSonic and now I am learning nHibernate since most of the prospective jobs I can go for use nHibernate.
The thing is, I have been programming based on what I have been taught, read or come to understand as best practice. Recently, someone through a spanner in the works and had me thinking. Up until now, I have been accessing the database(s) from both the core applcation and attached DLLs that I write.
What this persons said ends as follows and hence my question:
I can tell you
that you wouldn't normally want to do this - an external class library shouldn't have access to the database
What I was trying to do was to have a shared/static class for nHibernate sessions that could be consumed in both the global scope of the app and from any dll. This class was to be in a "core" DLL which all dlls and the application reference. Like I said I'm learning nHibernate so it may not be the way.
To say i'm questioning my database access methods is putting it lightly.
Can anyone put me straight on this?
Edit:
I suppose looking at what has been commented already, it depends on how the database is being accessed. I would tend never to put username/password credentials etc hardcoded in any DLLs for any means.
More specifically, my query is in relation to NHibernate's sessions. I have a static class, an helper class, which is called at application start and the new session is then created and attached to the current context, in the case of web applications, and then whenever I need the session I call "GetCurrentSession". This static class is in the "core" dll and can be accessed with any DLL etc that references. This behaviour is intended. My only question is is this ok? Should I be doing it another way?
A couple of reasons would be
Access to the database, how do you cover off username/password
sharing the DLL, a "bad" application may get hold of your DLL and link with it to get access to your database.
Saying this, if you have proper security on files, etc. then I would have thought using a DLL would probably be a reasonable way to go.
Assuming that the username and password are not stored directly in the DLL (but maybe passed as parameters, or passed as a complete connection object) this isn't so bad.
The possible bad practice here might be accessing the same database for the same purpose from different places - core app and DLL. This could get confusing quickly to a new developer, unless the separation is clear and logical.
Myself, I might try to move ALL (or almost all) data access to a DLL just for that purpose, then have the serious application logic (or as much as possible) in the core app or yet another DLL.
Does anyone else think Silverlight 4 security is a bit screwball?
Look at the following scenario:
Silverlight when set to trusted app, and run out of browser mode allows you to browse for a file using the file open dialog.
You require the name of the path of the file to open it up from any COM automation. For example (excel/word) but this could be anything.
It is impossible to get the full path of the file from the dialog because of security restrictions
You can however using COM FileSystemObject - do what ever you want to the users file system, including create folders, move and delete files.
So in other words, why all the fuss about security in Silverlight, which actually hinders real business use cases, when its possible to access any file anyways using COM?
To say it another way, if a user runs a malicious silverlight app, its unlikely they'll say - oh well it was COM at fault. The COM was afterall being called by a Silverlight app.
Here is what I mean....
User browses for file - c:\myFile.xls
Silverlight prevents you from getting the path (for security reasons)
Silverlight only lets you work with my documents
Using COM you can do what ever you want to the file system in the background anyways. Including copying that file now to my documents, if only you knew the name! But besides that you can wipe any file potentially if its not in use.
In my opinion Silverlight security model is flawed, either they should have given developers full trust and allow us to run apps as if they were running locally
or
Not allowed Silverlight to access COM.
Is it just me, or can anyone else see that its a bad implementation?
This triggers security alerts:
OpenFileDialog flDialog = new OpenFileDialog();
FileInfo fs = flDialog.File;
string fileName = fs.FullName;
This doesn't
dynamic fileSystem = AutomationFactory.CreateObject("Scripting.FileSystemObject");
fileSystem.CopyFile(anyFileName,anyDestination);
I don't agree with your point of view. The fact that you can do pretty much anything that an installed COM object will allow you to do is not a reason to modify a whole bunch of existing Silverlight code to allow you to do those same things.
Why? Because in the process of opening up that code there is also an increase chance that in some unintended way that same code could get run when the Silverlight component is not running in trusted mode. If that were to happen even once the media would all over it in a shot and Silverlight's reputation would, probably unfairly, be in tatters.
Personally I'm quite happy with the very cautious approach to security that MS are taking with Silverlight.
some Silverlight controls such as the OpenFileDialog work in both trusted and untrusted mode. These controls have been ported from previous versions of Silverlight where the new levels are elevated trust were not a consideration.
Thank you to Anthony for pointing this out.
Developers need to be aware of the definition of trust we are discussing here. Running a Silverlight application in full trust with elevated privileges IS NOT the same thing as running a local Silverlight Windows based Application. It is also far more restrictive than ActiveX.
Its possible that the trust here provided in Silverlight suits your particular business requirement. It is however likely that there are scenarios where you will find Silverlight too restrictive, its best to do your research upfront, and run code samples to ensure you can do the critical stuff, before jumping in head over heels.
Microsoft guarantees that public Silverlight API has the same behavior for both for Windows and MacOS platforms. So the functionality is many ways limited by the common denominator and technical feasibility. Please treat COM introp as a specific case addressing only Windows platform and only in full trust mode and it is not going to work the same for other platforms. So the security restrictions are valid as they are the same for both worlds in terms of API reuse.
I agree with the original poster. I think it's bad implementation. We are given a built in dialog to browse for a file, including directory structure. We can select a file and get a FileInfo object, but security prevents us from getting the FullName (directory and file name). Why? How does that improve security? What's the point of the open file dialog to begin with?
And as the original poster mentioned, with those dynamic objects, we can modify the local file system... which seems like the possible security hole.
All I want to do is read some data from an excel file... a way for my users to import excel data into the application, and the file could be saved anywhere on their machine. These are sales reps using an excel files to record orders locally until they can get to an internet connection. Who knows where they all save that file... so I'm not going to try to suggest we tell them all to store it in the same place in "my documents". I'll get laughed at if I suggest that.
It seems like it should be incredibly simple. But that "security measure" that keeps us from getting the directory the user chose from the built in open file dialog makes it so that we can't use the dialog for the purpose it was created for.
So what's the alternative? Is there a way to pick files using those dynamic objects? Do I have to write my own file selection tool using those objects that can modify the file system? Since I don't need anything but to read the file, and because I read something somewhere that we do have access to the file stream... is there a way to using the file stream to open up the file for reading using the AutomationFactory?
We're developing applications for AppExchange and are trying to figure out the best way to do development and release management. There are several issues around this:
1) Package Prefixes. We are developing code in unmanaged mode and releasing as managed, so we have to add all the package prefixes into the code. Is there a way to do this dynamically at runtime? Right now we're using an Ant script, which stops us benefitting from the force.com IDE plugin.
2) Resource files... We are doing some ajax-ey stuff and as a result have a few different resource files we upload, some of which are multiple file resources (zip files). Has anyone automated the building of these resources using ANT, and does that work well?
Our environment seems very fragile and works for some developers and not others; have other people had this problem? How did you resolve it?
I hate to say it, but it sounds like you've settled on the best approach that I know of. The Salesforce packaging environment can be a total nightmare to work with. Once your managed package has a prefix, there's really no going back to a plain package without one unless you script it like you've done. So you'll find the package name peppered throughout your code, which the system will add for you.
I've found the best way to work with it is to keep a "pure" version of your app, which will install cleanly into a dev org from within Ant. Once you have the code in Ant, it can be added into "normal" source control. It doesn't seem like too many larger scale apps have been built in Salesforce with multiple team members, because as far as I can tell, there isn't much support for a workflow that includes source code control. They tried adding some type of release management to a dev org configuration, which is now in beta, but it didn't seem that good at all.
I think Ant using the Salesforce Force.com migration tool is the way to go for the most part. Then, however, once you want to make a managed package, you're sort of stuck with that code base frozen, with that prefix, where you'll then have to do packaging releases (from beta, etc) from within the packaging system itself. The best way there is to refresh to sandbox (hard limit of once a month!!), then have developers pull out of that sandbox and deploy into individual dev orgs, which then can be merged periodically into a "group dev org", before deploying back into the Sandbox (using Force.com IDE or Ant), then into Production.
The whole process is basically a complete disaster. Salesforce is so close to having a super powerful platform, but a lot of the time feels like an awesome sports car without a steering wheel.
As far as static resources, those you should be able to automate in a relatively straightforward way using Eclipse, so that you can deploy those separately in one step. The API should support it, too.
I have worked on some rather large Apex code bases (I think, and hope), and there is really no apparent elegant solution, I'm afraid. You'll be stuck with strange combinations of deploying using Ant in some cases, Eclipse others, etc.
Coming from other development environments, it's often befuddling and just strange. For example, it's perplexing that you can't easily dump the database in one step while keeping track of relationships between objects and then "import" it into another org in one step. We actually had to write a tool that would make it easy to extract all data while traversing object relationships, load all data, recursively delete data, etc. from a xls file because we needed an easy way to test in orgs.
BTW, dev orgs are basically throw away orgs. We create dozens of them for different testing purposes and to keep different versions and configurations.
Sorry I couldn't give you better news. There might be more of a guru on here who can point to an elegant way to manage packaging, and I'll be as interested in you as the answer! You can email me at suprasphere --- at --- gmail if you want to commiserate! :)
We've recently switched to using a Prefix Manager instead of doing ant substitutions.
Here is our code.
public class PrefixMgr {
private static string objPrefix = null;
public static string getObjPrefix() {
if(objPrefix == null) {
try {
Database.query( 'select MyColumn__c from my_prefix__MySmallTable__c' );
objPrefix = 'my_prefix__';
}
catch(Exception e) {
objPrefix = '';
}
}
return objPrefix;
}
public static string getAppPrefix() {
return 'my_prefix__';
}
public static string getObjName(string inp) {
return getObjPrefix() + inp;
}
}
Basically this attempts a query (one time) against a table with the prefixed name. If it does not exist, then we are in unmanaged mode with no package prefixes. If it does succeed, then we set the prefix appropriately. getObjName is a convenience because PrefixMgr.getObjName('MyObject__c') is easier to read (esp in a string concat) than PrefixMgr.getObjPrefix() + 'MyObject__c'.
Interested in thoughts and comments.
I have been tasked with writing an installer with a silverlight out of browser application. I need to.
get the version off a local EXE
check a web service to see that it is the most recent version
download a zip if not
unpack the zip
overwrite the old EXE
start the EXE
This installer app is written in .NET WinForms now but the .NET framework is an obstacle for people to download.
The recommended solution is to use a SLOOB however i am not sure how to assign full trust. If i assign full trust can I start a process.
Thanks
Looking into this, I suspect you're going to have to create the process using WMI through the COM interface. At the end of the day, that makes this a very difficult option and very subject to failure due to a host of reasons (WMI being disabled or secured, user won't give full trust, etc.) I suspect you would be much better off creating a .msi deployment package or something similar that was able to go out and download the framework, if necessary. There are a lot of deployment models available, almost all of which feel superior to this one.
That said, if you're going to do this:
To get the COM object, you're going to want to use the AutomationFactory.CreateObject(...) API. Tim Heuer provides a sample here.
To actually do the WMI scripting, you're going to want to create the WbemScripting.SWbemLocator object as the root. From there, use the ConnectServer method to get a wmi service on the named machine. You can then interrogate the Win32_Process module to create new processes.
Edit: I spent a little time working on this and, even on my local machine as Admin I'm running into security problems. The correct code would be something similar to:
dynamic locatorService = AutomationFactory.CreateObject("WbemScripting.SWbemLocator");
dynamic wmiService = locatorService.ConnectServer("winmgmts:{impersonationLevel=impersonate,authentationLevel=Pkt}//./root/cimv2");
dynamic process = wmiService.Get("Win32_Process");
dynamic createParameters = process.Methods_["Create"].InParameters.SpawnInstance_;
createParameters.CommandLine = "cmd.exe";
wmiService.ExecMethod("Win32_Process", "Create", createParameters);
Silverlight 4 will have support for something like this: http://timheuer.com/blog/archive/2010/03/15/whats-new-in-silverlight-4-rc-mix10.aspx#sllauncher