Open antilibrary opened 6 years ago
I got the barrier when tried to get grapejs work. I will check what's the best way to remove the limitations of sandboxed iframe.
Thanks for trying to get grapejs to work on Zeronet. I hope to someday be able to create a nice site on Zeronet without needing to code anything.
Possible security problems of removing sandboxing (by default):
Solution: delete from global context before injecting the iframe
Solution: delete localStorage
then replace it with a object that only allow access to site's storage
Solution: Replace it with an object that only allow to change to url within the site's address
Solution: Put the sidebar to sandboxed iframe?
...
delete localStorage
will only delete window.localStorage
. It is possible that localStorage
object can be accessed another way, so delete localStorage
won't help.
@imachug I have not found other way to access localStorage, so proof-of-concept:
class RestrictedLocalStorage {
constructor (ls) {
Object.assign(this, {
setItem(key, val) {
console.log("set " + key + " = " + val)
return ls.setItem(key, val)
}
})
Object.assign(this, {
getItem(key) {
console.log("get " + key)
return ls.getItem(key)
}
})
}
}
restricted_localstorage_handler = {
get (target, key) {
console.log("proxy get", key)
if (key == "getItem" || key == "setItem") {
return target[key]
}
return target.getItem(key)
},
set (target, key, val) {
console.log("proxy set", key, val)
return target.setItem(key, val)
}
}
localStorage.setItem("test", "hello")
console.log("test:", localStorage.getItem("test"))
rs_ls = new RestrictedLocalStorage(window.localStorage)
rs_ls_proxy = new Proxy(rs_ls, restricted_localstorage_handler)
delete window.localStorage
window.localStorage = rs_ls_proxy
console.log("ls object:", localStorage.ls)
console.log("test:", localStorage.getItem("test"))
localStorage.setItem("test2", "hello2")
console.log("test2:", localStorage.getItem("test2"))
localStorage["test3"] = "hello3"
console.log("array-like test3:", localStorage["test3"])
Do you know if localStorage.set/getItem
is read-only? If it isn't, it would be more secure to use localStorage.set/getItem = ...
instead.
Yes it's possible (I have only tested all of this in Chrome yet), but it's also possible to use localStorage["anything"] = "other"
which I have not found a way to override
I have updated the poc code with array-like object access support using a Proxy (not sure if it's possible without it)
Looks interesting. Though I think some other ops like clear
should be allowed, but otherwise it's ready.
Unfortunately I found a way to recover the original localstorage object by creating an sub-iframe. So probably we can't protect cross-site localstorage access.
I have added a new NOSANDBOX permission in Rev3335 that should remove the sandboxed iframe restrictions.
As for example I created a demo for grapejs online html editor that is using iframes, so it did not works under sandboxed iframe restrictions: http://127.0.0.1:43110/1Grapes1bMdkcoM8CtjboJtPS1kvbtqMUj/editor.html
How can I use this NOSANDBOX permission. There is no sign in the content.json. Thanks!
I believe your zite has to ask for the permission to be added, then the user must accept that permission. I don't know the specific command to call to ask for the permission, but it's either in the ZeroFrame API Reference or will be.
You have to use the wrapperPermissionAdd command:
page.cmd("wrapperPermissionAdd", "NOSANDBOX", function(res) {
if (!res.error) page.cmd("wrapperReload")
})
I'm not sure if I understand how to use this. I've added to the zite and I grant the permission but when the page reloads the zite is still inside an iframe. I'm on rev 3354. The same happens with the zite you provided as example. Shouldn't it load the zite html directly instead of using the iframe? Thanks
The site will be in the iframe, but with the "allow-same-origin" permission which is disables the sandboxing restrictions.
Completely removing the iframe would be also possible, but then reaching the zeronet api would not be possible as it handled by the wrapper.
So I recommend to expose the required variable using window.top
after you granted the NOSANDBOX permission.
Completely removing the iframe will much easier for prerendering.
Thanks, @HelloZeroNet , Angular apps can now load (only tested static so far, no AJAX/WebSockets or use of DB).
Can you list the security concerns for NOSANDBOX, and why each visitor to the site has to Grant the permission after being prompted with a message suggesting it is "Dangerous!"? If you produce sample code for testing, can you please share that as well to help us test?
I saw a few concerns in this thread, but that was before you introduced this solution, so it isn't clear if they are still concerns.
I figured out what this permission does before finding your description here, sadly. lol At least I had fun learning.
Can you list the security concerns for NOSANDBOX, and why each visitor to the site has to Grant the permission after being prompted with a message suggesting it is "Dangerous!"? If you produce sample code for testing, can you please share that as well to help us test?
PoC:
// Get NOSANDBOX permission, then:
window.parent.zeroframe.cmd("configSet", ["open_browser", "cmd && rem %s"]);
window.parent.zeroframe.cmd("serverShutdown", [true]);
Wow, you now have a shell in ZeroNet console, which means that an attacker can possibly run any code on your computer, e.g. still keys or setup a cryptolocker.
TYVM, imachug! I really appreciate your help here.
I'm going to look deeper into this for possible solutions. Please feel free to share ideas you've looked at and thoughts on why they could or could not work.
The goal here is the ability to securely run common front-ends like Angular, Vue and React to help build the ZN community by attracting the best site developers with the ability to port investment they have made in both code and skills.
I do have some ideas. Instead of embedding site content into an iframe, you can insert an iframe into your site. @HelloZeroNet I can implement this (I have done that for my Alt-ZeroNet implementation already), but I wanted to check whether you're fine with it.
Do you have the latest py3 in Alt-ZeroNet? I'd like to test it.
Hopefully we can develop a security regression test suite at some point with this. For now, that just means coming up with tests and scenarios.
Do you have the latest py3 in Alt-ZeroNet? I'd like to test it.
No of course. Alt-ZeroNet is a completely different implementation. It uses NodeJS, not Python. It's also Work-In-Progress. I'm planning on speeding up development in September. There's no alpha/beta version yet.
What I was talking about is that I have implemented a part of ZeroNet already; more specifically, the ZeroFrame gate, and I'm currently porting it to the official implementation.
...you can insert an iframe into your site.
If the issue is exposure of commands reserved for the wrapper, how do you secure it if the IFrame is inside the user's pages? Seems either way, need to reduce commands that can be executed if a site has NOSANDBOX. No reason such a site needs "serverShutdown" or "configSet", for instance.
If we go this route, can we leave NOSANDBOX as is and create a new permission, because NOSANDBOX is useful for quick diagnosis. Once a zite dev determines that resolves their immediate issues, they can then compare a permission that restricts server-side commands, but doesn't require the site user to be prompted, to determine if the restrictions create new issues.
There could be a lot I don't understand, yet. I'm about to review the request handling code.
@github-zeronet
Uh... so there are commands that can be executed by the site and commands that can be executed by the wrapper. Everything that can be used by the site can also be used by the wrapper, but not vice versa. Take a look at ZeroTalk. It can read files, write files, sign & publish content, choose certificate provider, and... that's it. The wrapper (more specifically, the sidebar) need to do more stuff: change site size limit, list peer location, reload & rebuild database, pause, update and delete the site, and a few more things. Enabling NOSANDBOX
means allowing the site execute those commands, so the site could set its size limit to 1 TB and fill up your drive.
A lot better idea would be to make it such that there's no reason to use NOSANDBOX
at all -- i.e. moving the content out of iframe. My idea is to make a so-called iframe gate. Here's a small overview on it:
/Talk.ZeroNetwork.bit/
;index.html
contents;/ZeroNet-Internal/WebsocketGate
URL;/ZeroNet-Internal/WebsocketGate
;wrapper_nonce
);Content-Security-Policy: sandbox allow-scripts
header;<script>wrapper_nonce = "{wrapper_nonce}"; var socket = new Websocket("...?wrapper_nonce=" + wrapper_nonce);</script>
content;wrapper_nonce
nonce;.cmd
/.cmdp
;window.parent.sendMessage(..., "*")
;sendMessage
;Notice that Referer
[sic] is used here to check what site is using the websocket. However, Referer
header is not set for websockets, that's why we're using iframe.
That's a very well thought out design. What would be the ETA before we could test it?
Yeah it's an interesting design, but not sure if this way it's possible to do permission requests, the sidebar and you won't be able to do cookie/localstorage limiting.
@HelloZeroNet
but not sure if this way it's possible to do permission requests
Sure it is; I have little time to explain the details right now, but here's an overview: you can create an iframe with a gate document, set Content-Security-Policy: sandbox allow-scripts
for that document, and use shadow dom to position that iframe.
the sidebar
Same as above
you won't be able to do cookie
We can use path=/address
to limit cookies to a specific site.
localstorage limiting
This is a bit more difficult, but we can use the following trick: we'd store the local storage content in users.json
as we do with siteSettings
already; if we really want some consistency with localStorage
behaviour (i.e. unique to browser), we could fingerprint the browser with User-Agent
or something. Then, we'd first put localStorage to the prefix and then use that data to read localStorage, and then we'd use UiWebsocket to modify localStorage.
This means that compromising localStorage
(e.g. with an iframe) makes no sense because it's empty.
@github-zeronet No ETA yet, mostly because I can't predict it, but I'll tell you when I'll finish a PoC.
Please see my proposal at #2169. @github-zeronet
Would it be possible to add a flag that would allow a zite to be loaded directly instead of loading it inside an iframe? The problem is that for tools like vuejs-devtools to work the vue.js script must be present in the page itself. If the script is inside the iframe the tool won't detect the script. I could use that tool by loading the file directly on
file://
but then the zeronet api will not work. Maybe the flag can be set only if the person is the site owner.Thanks