Loading Defensive Code First: Critical and Painful
Single Point of Failure: How API Hooking Gets in the Way of Everything
Secondly, the security code needs to hook onto EVERY possible JS API for DOM manipulation, local or remote/network I/O, local IPC etc. The security code at this point is running in a synchronous blocking mode, stalling the loading of any subsequent resources on that page. Nothing else runs or loads until this hooking is complete, effectively making this process a SPOF (Single Point of Failure). This code is very different from user experience monitoring scripts that can run asynchronously and can live with sampling. So, what is JS API hooking and why is it needed?
Hooking is a general programming technique to filter pre or post a function to debug and inspect function parameters and results. In the context of security, this inspection can be used to enforce policies and/or monitor the program behavior. In order to provide comprehensive coverage with no gaps, all possible functions for a particular behavior should be hooked.
Further, the state of JS APIs across browsers is a complete mess given the number of APIs, the lack of support across the board, and the need for browser specific code. Researchers found that just the hooking operation itself adds an overhead of 8% (and in some cases, such as for eval(), the overhead could be over 10%). The cumulative overhead of inspecting or modifying parameters and results across 100s of APIs is detrimental to performance. For a lightweight inspection method the cumulative slowdown is ~ 20% and for full virtualization it could potentially be several times more.
Professor Somesh Jha, an expert in compiler optimizations, at University of Wisconsin, Madison, points out that such API hooking completely messes with the JIT (Just in Time) optimizations in most browsers. Almost all browsers (except Chrome) stop "Jitting" once the “to-be-optimized” code patterns get invalidated. (For a primer on JIT, click here). As per another leading expert in this field, “Wrapping APIs that take callbacks means you have to wrap the callbacks: if you use the same wrapper, that thing is megamorphic at best, but more likely it doesn’t get optimized. Changing prototypes of objects - this is super bad for some of the globals, array being the most performance sensitive.”
- Time to first byte (TTFB)
- First CPU idle
Even as API hooking degrades performance and negatively impacts user experience, the level of security your users get is insufficient. We’ll discuss the weakness of that security in an upcoming blog.