Security Domains

From PowerUI
Revision as of 17:04, 15 March 2017 by 188.222.158.94 (talk)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Nitro is a powerful scripting language which is streamable. This, however, means that somebody could potentially write some Nitro and change your scene to their benefit (or, for example, give themselves some bonus points).

So, there's a trade-off which we put in your hands. You don't need to worry about this security issue unless you change the settings. That's because, by default, Nitro coming from unsafe locations is entirely disabled.

Unsafe Locations

If the Nitro does not originate from your project, it is considered unsafe:

  • Only the body and head tags can contain scripts.

Let's say you have a chat box. That chat box writes straight to innerHTML when the person hits enter. Let's also say you forgot to escape it - an easy mistake (especially if you'd like people to be able to write HTML anyway - security isn't the first thing that comes to mind). It won't be long until somebody tries to write some scripts. As those scripts are not written straight to the body or head tag, PowerUI will act like they're just not there. As a handy tip if you'd rather not rely on this feature, either write to textContent or use Dom.Text.Escape(theString);

  • Hard coded Nitro (like in your Resources folders) is always considered safe. Anything else, such as from the web, will display a "Nitro ignored" warning message.

Creating a security domain

New JavaScript notice: The namespace that this is in will shortly be changing, but its functionality will be exactly the same - it would just apply to either real JavaScript or Nitro.

You can restrict Nitro's access of certain classes by creating a security domain for a particular document. You can either set it up on either a blacklist or a whitelist basis - i.e. allow everything except for x, or allow only x.

For some guidance, look for the class called UIScriptDomainManager. It's the default (and very liberal) security domain and can be found here in PowerUI 2:

  • Source/JavaScript/NitroV1/UIScriptDomainManager.cs

To define a custom security domain, you'll first need to derive from NitroDomainManager like this:

using System;
using Nitro;


public class MySecurityDomain : NitroDomainManager{

    public MySecurityDomain(){
    
        // Add a reference to a particular assembly/namespace:
        // (The first dot means 'this' assembly)
        AddReference(".PowerUI");
    
        // None of the types will be allowed by default.
        
        // You can either manually specify particular types that are allowed:
        Allow("HtmlElement");
        
        // Or whitelist all types in all references (not recommended unless you want to be very liberal!):
        AllowEverything():
        
        // Then block particular ones:
        Block("UISecurityDomain");
        
    }

}

Applying a security domain

Changing security domains is a security concern too (e.g. consider someone managing to override your safe security domain with the default one), so the safest way to change the domain is during startup. Manually call UI.Start before PowerUI has started:

// Call me in e.g. Awake:
UI.Start(new MySecurityDomain());

Due to the concerns about introducing multiple ways to change security domains, this domain is simply universal for PowerUI - once set, it cannot be changed (unless you edit the source of course!).

Per-Script security domains

It is very possible to define security domains for specific scripts however. Nitro can be used separately from PowerUI, and during compilation, you simply specify the security domain then:

using Nitro;

// Compile the code (throws exceptions on failure):
NitroCode code=new NitroCode("your nitro code",yourSecurityDomain);

// Instance a class optionally casting it to Nitro.Script, the default base class:
Script codeInstance=code.Instance() as Script;

If you go this route, of course be wary about where your security domain is instanced/ where it originates from (and make sure the user can't intercept that - e.g. they write one script which gives another universal access).

Specifying base classes is also a great way to work with high performance Nitro:

using Nitro;

public class MyBaseClass : Script{  // :Script is optional (but gives easy access to Nitro globals etc).
    
    public virtual string Hello(){
        return "";
    }

}

// ...

// Compile the code (throws exceptions on failure):
NitroCode code=new NitroCode("function Hello():string{ return 'Hello from Nitro!'; }",yourSecurityDomain, typeof(MyBaseClass));

// Instance a class:
MyBaseClass codeInstance=code.Instance() as MyBaseClass;

// Run the (overriden) hello function:
codeInstance.Hello(); // "Hello from Nitro!"