applications


Background Primer:

Logging. As developers we all need to do this, especially for deployments where it’s entirely unreasonable to ask our end clients to use / maintain / notify us of crash events, and even if they did it gives us a needle’s-eye view of the problem. So while interim development usually starts off with good ole trace it’s potential for releasing sensitive data into the stream is greatly amplified by either the type of application you are writing and it’s complexity. Just having a debugger running, we’ve all seen every one else’s trace statements.

Security:

So AIR helps take the LogLogger from the SDK and gives us the potential to write log files, typically in the application storage area. While this can and does help the alpha and beta stages of release to end-clients it significantly increases their exposure of sensitive data because now you are writing it in area where only the user needs privilege – not admin.

The Better Approach:

Because we want to use the ILogger interface along with standard LogEvents (because Targets use these), the LogLogger is easy enough to re-write. With each message being ultimately broadcast in the event – this is the most appropriate domain to intercept, scramble, and resend. I started with each defined interface method and before each dispatch, a new method is used to build/construct the message. With the help of an implementation of a secure logger (composition goes a long way to help swap parts out instead of inheritance), this class is tasked with doing the actual work of rewriting or removing selected properties from objects we need to keep secure.

The Implementation:

The key with the build method is not only to introspect top level objects as part the …rest parameters, but also to see if anything is an array and to iterate that list to make sure the class type is or isn’t the type that needs to be secured. Any object which needs to be secured is then sent through the secure logger, otherwise a straight obj.toString() is used.

 

LogLogger

public class LogLogger extends EventDispatcher implements ILogger
{

private var _secureLogger:SecureLogger;
private var _category:String;
private var resourceManager:IResourceManager = ResourceManager.getInstance();

public function LogLogger(category:String)
{
super();
_category = category;
}

public function get category():String { return _category; }

public function log(level:int, msg:String, … rest):void
{
if (!hasEventListener(LogEvent.LOG)) return;
msg = build(msg, rest);
dispatchEvent(new LogEvent(msg, level));
}

public function debug(msg:String, … rest):void
{
if (!hasEventListener(LogEvent.LOG)) return;
msg = build(msg, rest);
dispatchEvent(new LogEvent(msg, LogEventLevel.DEBUG));
}

public function error(msg:String, … rest):void
{
if (!hasEventListener(LogEvent.LOG)) return;
msg = build(msg, rest);
dispatchEvent(new LogEvent(msg, LogEventLevel.ERROR));
}

public function fatal(msg:String, … rest):void
{
if (!hasEventListener(LogEvent.LOG)) return;
msg = build(msg, rest);
dispatchEvent(new LogEvent(msg, LogEventLevel.FATAL));
}

public function info(msg:String, … rest):void
{
if (!hasEventListener(LogEvent.LOG)) return;
msg = build(msg, rest);
dispatchEvent(new LogEvent(msg, LogEventLevel.INFO));
}

public function warn(msg:String, … rest):void
{
if (!hasEventListener(LogEvent.LOG)) return;
msg = build(msg, rest);
dispatchEvent(new LogEvent(msg, LogEventLevel.WARN));
}

private function get secureLogger():SecureLogger { return _secureLogger ||= new SecureLogger(); }

private function build(msg:String, params:Array):String
{
var repl:String =”;
for (var i:int = 0; i < params.length; i++)
{
var obj:Object = params[i];
if (!obj) repl = ‘null’;
else if (secureLogger.hasReplacementRule(obj))
{
if (obj is Array)
{
var n:int = (obj as Array).length;
for (var j:int = 0; j < n; j++)
{
var child:Object = obj[j];
repl += secureLogger.getReplacement(child);
}
}
else repl = secureLogger.getReplacement(obj);
}
else repl = obj.toString();

msg = msg.replace(new RegExp(“\\{“+i+”\\}”, “g”), repl);
}
return msg;
}
}

SecureLogger

public class SecureLogger
{
public function SecureLogger()  { super(); }

public function hasReplacementRule(obj:Object):Boolean
{
if (validateReplacementRule(obj)) return true;
if (obj is Array)
{
for each (var child:Object in obj)
{
if (validateReplacementRule(child)) return true;
}
}
return false;
}

private function validateReplacementRule(obj:Object):Boolean
{
if (obj is Account) return true;
if (obj is LoginCredentials) return true;
return false;
}

public function getReplacement(obj:Object):String
{
var str:String;
if (obj is Account) str = secureAccount(Account(obj));
else if (obj is LoginCredentials) str = ‘[LoginCredentials]‘;
else str = obj.toString(); return str;
}

//An example of using regex to re-write sensitive data
//Since it’s working with direct string manipulation, it must know about it’s format
private function secureAccount(obj:Account):String
{
var str:String = obj.toString();
str = str.replace(/number=\d+/, ‘number=’+ obj.id +’ ‘);
str = str.replace(/name=.*?(?=type)/, ‘name=Account ‘+ obj.id +’ ‘);
str = str.replace(/institutionName=.*?(?=institutionWebsite)/, ‘institutionName= Institution ‘+ obj.id +’ ‘);
str = str.replace(/institutionWebsite=.*?(?=status)/, ‘institutionWebsite= ‘); return str;
}

}

The entire OLAP package in Flex has sparse API documentation, but there are several ‘how-to’ examples out in the land of live-docs. This usually doesn’t bode well, because it generally means a tech-writer never talked to the development team to figure out what all the dependencies are on the various properties. We have the source, but chasing it down ourselves sucks.

 

A precursor into what doesn’t work:

  • OLAPAttribute.displayName does NOT work on subsequent dimensions. It will only work on your first dimension which is usually the ROW_AXIS. However, the OLAPLevel.attributeName will always expect to look up the OLAPAttribute.name.
  • The allMemberName even though it’s defined on the OLAPHierarchy, it must be actually set on an OLAPAttribute which is displayed for that dimension.

Now onto the real problem:

Generally to sort your cube, you do a 2-dimensional sort to the original flat dataprovider then assign this to the cube dataprovider.  And in most cases this seems to work OK, until your CATEGORY_AXIS is based on anything to do with Time (which is a lot of the time actually). In most cases you’ll have a two-tier hierarchy of year and month / quarter, but the problem appears to be most prevalent with months. Even though your original source is sorted correctly, some months will be placed out of order, especially if you’re using the allMember level which it builds on the fly in the query.

The Fix:

So the fix involves re-arranging the member IList in building the OLAPQuery to the appropriate OLAPSet. In addition to fixing the sort issue, now is the time to re-arrange the allMember level to where it seems logical for your application. Accounting applications generally read left-to-right, so summary total’s are generally shown on the right hand side.

The way know if you’re working with the allMember level that it created for you in the sort method, is to look for the OLAPMember.hierarchy.allMemberName and compare that to the current OLAPMember.name

The way to correctly resort months involves a bit of kludgery but I haven’t found a more elegant way around it. In the OLAPAttribute for the dimension you specify the dataField to the integer of the month (generally this is string from a formatter), and assign a displayNameFunction to use a DateFormatter to turn this into something meaningful at the UI level. Even though the name of the OLAPMember is a string, it’s actually a string cast of the original value to the dataField (hence the actual integer value). You can then re-cast this back to an int to do a numeric sort (so you don’t end up with 0, 1, 10, 11, 2, 3, etc).

Now you might think an easier way to do this is to just use a SortField, however since you’re original Object is transformed to a flash_proxy and lost in the process relative to the OLAPGrid, the internal numeric sort method to Sort will throw an error that it can’t find the property that you originally wanted to sort on (eg month).

This should get your columns back in the order in which they were meant to be in.

private function getQuery(cube:IOLAPCube):IOLAPQuery
{
… //Setup the rest of the dimensions / sets to associate to the correct axis

var list:ArrayCollection = cube.findDimension(“timeDimension”).findAttribute(“Month”).members as ArrayCollection;
list.sort = new Sort();
list.sort.compareFunction = compareSortMonth;
list.refresh();

var moSet:OLAPSet = new OLAPSet();
moSet.addElements(list);

private function compareSortMonth(a:OLAPMember, b:OLAPMember, fields:Array = null):int
{
if (a.name == a.hierarchy.allMemberName) return 1;
else if (b.name == b.hierarchy.allMemberName) return -1;

var aMonth:int = parseInt(a.name);
var bMonth:int = parseInt(b.name);

if (aMonth < bMonth) return -1;
else if (bMonth < aMonth) return 1;
else return 0;
}

Highly flexible applications and highly secure applications are usually at the opposite ends of the spectrum and require some sort of constant balance. So how do you mitigate your security risks when you need to build an application that is dependent on running modules at runtime via some sort of configuration?

ApplicationDomain.currentDomain is the just about the worst thing you can do when trying to build a secure application.

The problem:
Your modules are loaded at runtime which need to interface internal code you’ve written in your main application. This means the ModuleLoader needs to then set the currentDomain to ApplicationDomain.currentDomain. However ideally the module loader needs to be able to distinguish levels of trust if it’s a module you (or trusted developer) have written, or a rogue module.

The ugly issue:
When using a blanket statement to allow all modules to load with the currentDomain, you are giving every loaded swf trusted access to your entire platform. Some cases, this isn’t a big deal. It becomes a nasty headache if you’re building an e-comm solution. It will allow man-in-the-middle attacks to allow someone to load their module, and using any number of methods for decompiling and introspection to figure out what class and methods are used to capture and/or listen to events for sensitive information like user info and payment tokens. Their swf only needs to add itself as an IEventDispatcher or through the document tree to add itself to the sensitive classes and wait for these methods to be triggered.

The solutions:
There are several different ways to help combat this problem, however some are better than others. Any solution pretty much involves using 2 ModuleLoader’s. One for secure / trusted, another for insecure untrusted. Always start the loading process from the insecure, then based on which method you choose -transfer the loaded swf to the untrusted ModuleLoader via addChild(), swapChild(), etc.

  1. Use a trusted Interface in your platform that is always loaded at the application layer. However this is the weakest of them all since this only provides a minimal level of security as it can still be broken. The most flexible Modules use -load-externs as a compiler command to allow most of the dependent classes to be front loaded to the application. This makes things a bit speedier especially when loading several modules that share an entire platform. By using an internal interface you can check at the ModuleLoader level if the loading module has sufficient trust to be given access. This works in theory since the Flash AVM will not replace a duplicate namespace collision, but can still be defeated since I can write a rogue module and duplicate the secure interface using the exact same package.
  2. Use server side methods to generate hash key’s in the configuration which matches the particular node of the module in question. NEVER use this method in conjunction with deciphering the hash key internally, it’s way too easy to figure out what’s going on in your code. Instead pass this hash key back to the server, ask it to validate it against the file name and it’s own interally identifiable metrics (eg file size, mod date, etc) to then pass back a Boolean pass/fail for trust. Based on this service, then assign which domain it can be loaded into.
  3. Use a domain trust method in a static and final class to determine if the source of the module’s URL is coming from a place that is trusted. This basically means using RegEx along with hardcoded strings to determine if the URL is from ‘mydomain.com’. While this can be a bit laborious since it might require constant care to edit the domains that are trusted, however this particular solution isn’t as easily defeated since the list of trusted domains are embedded in your application.

I’m putting this out there as a give back to other Flash-Flex developers that want to use Joomla! as a data repository for any projects, in part because Rune Skjoldborg Madsen has taken the time to build specific component views in php to change the transport layer to XML.

(more…)

For anyone who might have noticed, especially if you’re coming from the flex showcase, the FlexPress application has been put in a suspended state of “permanent maintenance”. There are several reasons for this:

  • The xml-rpc.php gateway (at least as of version 2.4) had to behackedin order to inject additional methods to retrieve standard queries based on predominantly consumer-based methods. If you check the downloads section, it included things like getting data for blogrolls, comments, and a list of posts -where you only want the id’s and intro (useful for high volume). However because it was ‘hacked’ it made it impossible to keep up with the latest install. Since my php skills are elementary at best, it worked for the time being but it definitely had a short shelf life -if I put some time into it (read: not likely with home life), I could probably figure out how to extend the IXR gateway class to inject my own dependencies. With a recent update to 2.8 to eliminate annoying comment spam, this obviously broke the gateway, but broke it even further since I relied on SQL queries to get some of this data directly from the tables -however the tables have completely changed.
  • I’m at a point where I need to start giving serious consideration to updating the ‘portfolio’ side of things, however I’ve put it off as long as possible because while design-wise it still fits with the presentation I want, the management of data is gnarly at best. It was designed/developed with Dreamweaver, but as completely static html using templates -good at the time but considering the maturity of app services using any sort of DB, it finally makes it possible to do things that couldn’t be achieved with static content: popular views, most current views, segregation of recent projects vs. archived material, etc. Using Joomla -I decided on this primarily for the extensive plugin library that makes it possible to build not only a front-end layer (by getting to just the raw data -see my other post about this -for anyone who wants to do the same thing but with traditional fixed property classes) but also in a TeamSite-ish way, this is where I’ll be concentrating my efforts (when I have them) for the time being.

Since the portfolio would be a 2nd ‘mini’ app I would be building (in Flex of course), it gave me an idea to build an overall Portal application that can load and interact with Portlet modules -this of course being an excellent example of some of more indepth things you can do with Flex (especially if one builds cross gateway functionality -ie Mash-Up to either add/modify or implement interactive services from one portlet to another). One of the neat things that makes it possible in building modular applications, is if one was adventurous enough, could event build a second UI layer to manage the administration of the back-end functionality. Initial Portlets that will eventually be built:

  • The Portfolio (and Archive) with it’s Joomla back-end.
  • The FlexPress with a WordPress bank-end will be resurrected -most if not all of the UI will be re-incorporated but obviously the entire data services layer will probably have to be updated in a meaningful way.
  • A Gallery: this won’t be open to the public since it’s the media management center for our family -but I’ll screenshot it as a app in the portfolio.

I don’t make any promises of it’s current status since it’s very much still an development release (read: expect an occasional crash, plain ‘halo’ styles, and some parts just aren’t implemented yet) -but if you’re curious to see how this is turning out, you can check it here.

This one crept on me and while I thought I was on the right track it wasn’t until I came across a tech-note on Adobe’s site that finally led me down the right path which incidentally I only found by accident. The main issue was a SecurityViolation Error which is common place in dealing with accessing data in different domains. Usually we all know about this, and is fixed in implementing the correct subdomain accessor in the crossdomain.xml however even after it was deployed the app was still throwing this error, which made me now think the wildcard initiator doesn’t work as intended.

It turns out that not only does your crossdomain need to have the allow access from node, if the page and requested data use different protocols that a secure attribute must be added.

When your application is in HTTP and you want HTTPS data use:

allow-access-from domain=”*.mydomain.com” secure=”false”

WHen your application is in HTTPS and you want HTTP data use:

allow-access-from domain=”*.mydomain.com” secure=”true”