Skip to content

Instantly share code, notes, and snippets.

@rehanift
Created July 17, 2012 01:19
Show Gist options
  • Save rehanift/14cda03c79b1ae33c020 to your computer and use it in GitHub Desktop.
Save rehanift/14cda03c79b1ae33c020 to your computer and use it in GitHub Desktop.
Javascript Secure Sandbox Notes

https://groups.google.com/d/msg/nodejs/P-gUjRun2Ek/hDXdS704w_MJ

  1. Use a child process to run the code. This process can be a node process that is running another VM inside of it for user code to be run in (it both the process and separated VM).
  2. Chroot the child process / Jail it / Run as Nobody:Nobody / run it in a new session / run it with empty environmental variables / remove ALL globals from node by setting them to undefined (not null) / everything reasonable to lock down the environment.
  3. Use a serialization channel when talking to user code, never ever directly share objects.
  4. Never reuse a child process.
  5. ANY variable given to a child process for interaction with a parent should be through a strict mode function that can talk to code outside of our VM, never give direct references to objects from the privileged vm. This function should be generated inside of the user code context prior to executing any user code and should not use eval(). All references to objects including functions from the privileged context should be done via a closure. Any arguments passed through the function should be serialized via JSON in the user context and parsed in the privileged context. NEVER PASS FUNCTIONS TO YOUR PRIVILEGED CONTEXT (this includes proxy handlers / getters / setters / toString / toJSON / valueOf / ; those should be calculated via the original toJSON call). Finally, the function should not use the this keyword.
  6. Set timeouts to kill your child process by.
  7. Use memory monitors outside of your child process to manage size.
  8. You should never run the debugger on your child process.
  9. Run the code.

https://groups.google.com/d/msg/nodejs/P-gUjRun2Ek/FfrSE8bTrgoJ

forgot to write down: any exceptions you get from the user code vm should not be inspected. Getter / setter traps on these are brutal, and since you can throw any kind of object, don't do it. wrap the user code in a try/catch and serialize it up to the privileged context.

https://groups.google.com/d/msg/nodejs/P-gUjRun2Ek/B0PZCGuQ7OMJ

You realize that what you're discussing here is a blacklist, which has been shown again and again to be an ineffective approach to security? If you have any thread back to the original context at all, it's going to be a hole. You'll never plug all of them. The only effective security is a small whitelist of allowed behaviors, in an isolated environment, where every message coming out is scrutinized by the parent process. Just run the code in a child process, as a user with no privileges, in a chroot (or better yet, a vm/zone/jail), monitor the memory usage and kill it after a timeout, and if you must, communicate with it through message-passing only. It's not perfect, but you can be damn sure that your operating system is a lot better at this sort of thing than any of us are, and it's a lot easier than the hoops that everyone is trying to jump through here.

All the stuff about restricting globals or whatever is kind of pointless at that point. Just lock down the underlying system, and then it doesn't matter.

https://groups.google.com/d/msg/nodejs/P-gUjRun2Ek/E4BH4uv5600J

Hi Marcel, thanks. Since NodeJS is a) not a browser, and b) can run a recent version of v8 which is adequately compliant with EcmaScript 5, the most relevant portion is SES (Secure EcmaScript), which achieves these security properties without translation. See http://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/, also found at http://code.google.com/p/es-lab/. The initSES.js script which is built from these sources is at http://es-lab.googlecode.com/svn/trunk/src/ses/initSES.js or http://es-lab.googlecode.com/svn/trunk/src/ses/initSES-minified.js.

To see whether a given browser's ES5 implementation is adequate to support SES without translation, visit http://google-caja.googlecode.com/svn/trunk/src/com/google/caja/ses/explicit.html in that browser. Chrome 16.0.912.10 canary passes, as does WebKit Nightly. The development tips of all other major browsers are expected to pass shortly.

My presentations and interview at the QCon SF and QCon London, at http://www.infoq.com/presentations/From-E-to-EcmaScript, http://www.infoq.com/interviews/ecmascript-5-caja-retrofitting-security, and http://www.infoq.com/presentations/Secure-Distributed-Programming, explain more about SES and the next steps we plan to take -- Distributed Resilient Secure EcmaScript (Dr. SES) -- which is essentially SES plus Kris Kowal's Q library, all of which Kris has gotten running on NodeJS.

https://groups.google.com/d/msg/nodejs/ae-YoX2YYJo/hogYmowKc4YJ

  1. Override Function, eval, Function.prototype.call, Function.prototype.apply, toString, valueOf, and toJSON as hooks.
  2. Add getter / setters for all values as hooks into possible places to poison any context this is run in (aka outside the sandbox access or into sandbox access === baaad).
  3. Override prototypes to repeat this if any of them is called (aka viral).
  4. Always check your function's .caller chain and use a try/catch (the exception can leak nice info) (dont use arguments.callee in case you got stuck in strict mode).
  5. Type coerce anything given to you and see if it uses the same built in native/host objects (it may have come from another context to infect!).
  6. Function.toString and see if it mixes the ""this" keyword with globals (this one is amazing)!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment