-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Question about securely vs endo #37
Comments
Hi @tgrecojs - great question. Allow me to explain.
Why Securely?When I created Snow (same goes for Across btw) I realized it won't be possible to do so without a truly secure way to call native functionalities, because if I want to create a standard shim for hermetically owning newborn realms - which is an action that must take place synchronously and atomically - the shim must perform its actions based on browser native APIs that must not be potentially monkey patched by an unknown entity in runtime. I have a lot of professional experience in handling with native APIs and monkey patches, and therefore thought it would make sense to finally come up with a third party library that does take full and exclusive responsibility for managing your access to native APIs to allow you to consume those securely. An important criteria I set for myself was to make sure this library's API will be as simple and as close to non-existing as possible. I wanted to avoid having to do stuff like this: const nativesLib = require('natives-lib');
const realFetch = nativesLib.getFetch();
realFetch.call(window, MY_URL); because I wanted to find a way to keep it as close as possible to how you'd use native APIs normally. I came up with a lot of ideas and decided that rewriting the native property to its original object with a minor modification is the best way to go as there is literally only once character difference there: const nativesLib = require('natives-lib');
nativesLib.activate();
window.fetchS(MY_URL); In addition, since the new property is written to a global object, I didn't want it to be accessible to anyone anytime, so I exported a special callback that only from within it these special props are accessible: const nativesLib = require('natives-lib');
const securely = nativesLib.activate();
window.fetchS; // undefined
securely(() => window.fetchS(MY_URL));
window.fetchS; // undefined This allowed me to keep a clean (IMO) API usage while not exposing native APIs to all entities in runtime, and that is how Securely was born Why not Securely?Well, it turns out there was a lot I didn't consider when designing Securely which I later realized thanks to the excellent feedback of experts like @mhofman, @naugtur, @kumavis, @kriskowal and @erights. Securely's design is completely vulnerable to prototype pollution - that special props Securely leaves can easily be redefined by other entities on objects I leak/return from Snow. You can leverage this ability to lie to Snow about questions it asks about objects you control as the attacker and by that convince Snow that it doesn't have to apply its protection for a certain frame for example. Understanding that is when I realized my dream for a natives management library cannot be fulfilled the way I thought it could, which made me realize that the native management that IS possible does not justify implementing a separate library. This is why in the last PR #36 Snow officially abandoned Securely, and once Across will too (soon), I will probably nuke Securely for good. Why (not?) Endo.js?I created Securely, Snow and Across before I even heard of SES initiative, but that is not the main reason for why Snow doesn't use SES atm. My javascript security experience is almost exclusively in the realms of the browser. And in the browser, not like in NodeJS, monkey patches are common, almost normal. Third party vendors use monkey patches for providing different services (security, monitoring, etc) and that is just normal in the industry. Having most of my experience in building and researching similar services, my approach for browser based technologies and shims is usually always around "leave the environment the same as you found it". In other words, when applying Snow for example I made sure that Snow's applied logic does not harm any normal behaviour the browser/website provide unless it really has to, and continues to allow the rest of the app to apply monkey patches if needed - such is the browser ecosystem (for now?), whether we like it or not. Therefore, performing SES lockdown and freezing properties of the entire runtime environment goes against how I think browser based shims should behave, and I tend to believe running such an intrusive shim in browser based web apps and websites will not integrate smoothly with those. On this the Agoric and I disagree, but it is important to note that the native properties SES lockdown freezes are the environment's intrinsics only which according to @erights is just the right amount for web apps to continue to run smoothly even with Endo.js shim running. I might try integrating SES with Snow at some point to test that theory out, but that is the current situation. Bottom lineThe bottom line is that SES's approach is more intrusive than what Securely was trying to achieve and what Snow implements for itself now, and IMO in the browser ecosystem that doesn't necessarily fly. And while this is of course always open for debate, that is the so called "blocker" you were asking about. Hope that makes sense! |
Thanks for the thoughtful response. You definitely cleared it up. 🙂 Here are some comments:
I understand this sentiment, but I'm not sure how well it meshes with securing JavaScript applications. "leaving the environment the same as you found it" and "hermetically securing JavaScript" seem conflicting ideologies. IMO, There will need to be a trade-off between APIs becoming unforgeable and ensuring users don't lose access to native APIs, at least in the short term. I find that the benefits will greatly outweigh the costs. Additionally, I think it's OK to be obtrusive in certain instances as long as that obtrusiveness provides a better outcome for users. I messed around with securely and was surprised that users could still access APIs they opted to secure. I feel like this would lead to many instances where developers accidentally use insecure native code APIs, especially in large systems, and it would benefit users to remove access to the APIs they wished to freeze entirely.
I agree that most existing applications would have a tall list of obstacles they would need to overcome if they wished to harden their program. I'm not sure how feasible that is. I agree with @erights regarding SES exposing "just enough" native code needed to build robust JavaScript applications. Still, I think that that job requires the program to be built from the ground up, instead of working out of the box with existing applications.
I'm wondering if there is a pathway in which Snow could be selective about freezing certain native code, without affecting the behavior of others. Just thinking out loud here, but there is TinySES and Jessie, which provide subsets of the SES. By no means am I a security expert. My background is building out reusable, deterministic programs, mainly written in JavaScript, but I've worked across all parts of the stack. My team is building financial software using @Agoric's framework, which is how I was first introduced to the SES movement. Needless to say, I am deeply appreciative of all the work being done in this realm, and hope to contribute to its progression where I can. That said, I'm interested in hearing your thoughts on my feedback. |
Maybe a better phrasing would be "leaving the environment functioning the same as you found it" and in that case I don't see a conflict. I think Snow is an excellent example for having the best of both of these worlds. It's also important to mention that Snow is a shim and ideally we'd like to see it as a builtin API exposed by the browser (WIP). In other words, the monkey patches Snow-shim has to apply in order to function are indeed not how we want to see such a protection implemented.
Can you demonstrate by example what you mean by But again, as mentioned in my previous reply to you:
I honestly think (and again, feels like I'm the only one) that freezing and hardening a web app is problematic. A big part of the industry of 3rd party vendors for websites legitimately relies on monkey patches and counts on the rest of the app to legitimately go through their patches in order for the vendor to provide its service. When Sentry hooks This is where @erights claims that those 3rd party vendors will monkey patch almost only non-intrinsics (e.g. The bottom line of what I'm trying to say is that hardening javascript apps such as NodeJS servers or browser extensions which are expected to acknowledge zero dynamic updates and only version updates is perfectly fine and a goal we should aim for. But with web apps and websites, which dynamically change and include 3rd party vendors that update their code externally all the time without the website having any control over, where those vendors continuously monkey patch native APIs as part of their legitimate service - I don't see how that works with an entirely hardened app.
Snow's job is at no point to freeze any code. Snow's job is to give you full access to every new realm that comes to life within your app, because realms can be maliciously leveraged against the app and therefore it's only fair the app would have primer control over all realms. If Snow can achieve that goal without freezing anything in the app that is far better than having to freeze anything, because its not Snow's job to protect native functionalities, that's SES job. Snow doesn't need to freeze natives, but it does need access to those. That was Securely's job, but since Securely turned out to be flawed, Snow now manages access to natives by its own rather than using Securely. But whether it uses Securely or not, freezing anything is not in the security responsibility of Snow, that is why SES is not very relevant to Snow IMO.
When the program you write runs on an environment you control and expect, using SES is only reasonable. When your program is expected to run on an environment you don't control with code from other vendors that updates whenever and keeping it determinstic is not always under your control - SES IMO might not always integrate so smoothly. Lucky for you, your work falls under the former group 😅 (right?). These are my opinions and they do not officially reflect anyone, and currently most of my colleagues disagree with me, so take most of what I say with a grain of salt (I wouldn't be surprised if I changed my mind anytime in the near future). What do you think? |
hey! @weizman this is an awesome project you've created here. These types of efforts are going to have a massive impact on securing JavaScript code regardless of the environment in which it's running. 🙂
I read through the snow wiki last night and it's a really interesting problem you're setting out to solve here. I have one question regarding Snow's use of securely.
After you explained the role securely plays in the Snow standard, you mention the following:
I'm wondering how securely's approach to freezing native APIs differs from the approach Endo takes with
lockdown
andharden
. It seems like something is currently blocking securely from using any of the Endo APIs at this point. But there may be a plan to integrate Endo APIs at a later time.Are these accurate assumptions? And if so, can you add context into what that blocker may be?
Thanks again for your work here!
The text was updated successfully, but these errors were encountered: