bunsenbrowser / bunsen

🔥 Bunsen Browser provides easy to use offline P2P application and file distribution that is verifiable on Android devices. https://bunsenbrowser.github.io/
117 stars 7 forks source link

Security issue: Cookies, local database, etc. on a Dat available to every Dat #30

Closed rjcorwin closed 6 years ago

rjcorwin commented 7 years ago

Because every Dat is served through an iframe to the Dat Server at localhost:8080, every Dat site will end up sharing the same browser domain sandbox thus the same databases, cookies, etc. We could start by every time a user requests a new Dat UUID, we enumerate the last port used by Dat server, and serve that Dat UUID on that new port. We then store the mapping of Dat UUIDs to port numbers in perpetuity on that device.

This does have the downside that the total number of Dats you ever visit is limited by the number of ports available. Given that Android does not claim a lot of ports, there might be in the tune of 64,000 ports available (https://serverfault.com/questions/103626/what-is-the-maximum-port-number). That could last a while, how many Dat sites can you visit? ;)

fuzzyTew commented 6 years ago

a simple (possibly insecure) solution would be to use subdomains of lvh.me (which resolves to localhost) for dat sites

rjcorwin commented 6 years ago

@fuzzyTew *.lvh.me, how did I not know about that? That's great. While it may be vulnerable to some attacks similar to using ports, it will allow us to have many more security namespaces.

rjcorwin commented 6 years ago

@fuzzyTew @chrisekelley I may have found an annoying quirk about lvh.me that makes support for this a little bit more of a hassle than it could have been. I wanted to build a concept server that you can access any dat by hitting it at http://<dat archive uuid>.lvh.me but it turns out that the dat archive uuid's are exactly one character too long for lvh.me.

e 63 times. It says error but this is still good, we are getting a response from the server.

screen shot 2018-04-06 at 9 23 12 pm

e 64 times and lvh.me can't find our server.

screen shot 2018-04-06 at 9 23 19 pm

FWIW, here's a server in 38 lines of code that if lvh.me didn't have this limitation would work by loading the dat by hitting http://<anything>.lvh.me/add/<dat archive uuid> and then http://<dat archive uuid>. It would be a nice trick to not have to hit that add route first but if we can't put dat uuids in the subdomain this might be a dead end.

xloem commented 6 years ago

@rjsteinert : Hi, I'm also fuzzyTew, have to merge my accounts ...

Another solution would be to put some of the data in the port.

Other options include sub-subdomains, or just trusting that as many bits as are available in the domain name would still significantly increase the security of the cookie situation.

It seems the best solution might be to add the necessary properties to a subdomain controlled by the dat team. Then you're not relying on the owner of lvh.me not to hijack anything.

rjcorwin commented 6 years ago

@xloem @fuzzyTew - Subdomains are definitely very important for the cookie security situation. I was thinking over the weekend to get around the issue of the character limit in subdomains of *.lvh.me that the server could maintain it's own mapping of Dat UUIDs to local short names that are actually used for the subdomain. For example..

Go to http://lvh.me/2698e1435add0324c7c99c52025b79befc9ee89e0262c8c2889b198d16852598, the server downloads that dat, makes a dat UUID to local subdomain mapping perhaps taking the last six characters from the dat UUID, and then forwards you to http://852598.lvh.me.

rjcorwin commented 6 years ago

Oh man. Found something interesting today that on a Lenovo Tab with Android 7.1.1 that the character limit for lvh.me subdomains is 64 characters as opposed to the 63 character limit that we see on Mac OS X.

rjcorwin commented 6 years ago

screen shot 2018-04-09 at 1 37 10 pm

xloem commented 6 years ago

@rjsteinert I just want to reiterate that relying on lvh.me to always forward to localhost should be considered an inferior solution, as the owner of lvh.me could change it. Additionally, DNS has the unfortunate attribute that an adversary could point it elsewhere, as it must query a server to resolve.

A better solution is to run one's own domain as mentioned earlier. An even better solution would be to modify the browser to handle the domain, offer a SOCKS4a or SOCKS5 proxy to parse the domains, or configure the machine to resolve the domain locally.

The 63 character limit sounds like a bug in Safari!

rjcorwin commented 6 years ago

A better solution is to run one's own domain as mentioned earlier. An even better solution would be to modify the browser to handle the domain, offer a SOCKS4a or SOCKS5 proxy to parse the domains, or configure the machine to resolve the domain locally.

Those technologies are new to me but they sound like they might be the ticket. Do you think they can be worked as a solution in an Android App? Would the device need to always be online?

The 63 character limit sounds like a bug in Safari!

Hehe, ya sounds like it. I actually experience that in Chrome on Mac OS X but I should try other browsers.

I made a quick proof of concept of the Dat Archive UUID to shortname mappings concept.

lvh-support

xloem commented 6 years ago

modify the browser to handle the domain, offer a SOCKS4a or SOCKS5 proxy to parse the domains, or configure the machine to resolve the domain locally.

Those technologies are new to me but they sound like they might be the ticket. Do you think they can be worked as a solution in an Android App? Would the device need to always be online?

I'm thinking configuring the browser (to use a different domain name server, or a proxy, or use a different code path to resolve domains) would be the way to go for an android app ... Although the others alone may be possible, they might require root access or at least special permissions. Those solutions are all intended to not require the device to be online, because any server is running locally.

creationix commented 6 years ago

DNS doesn't support segments longer than 63 characters. The solution I had was simply to re-encode the dat public key as a more compact base. You could use base32, for example and come in well under the 63 char limit. Another idea is to split the hex version into two segments.

creationix commented 6 years ago

https://github.com/creationix/host-dat/blob/master/auto-dat.js

rjcorwin commented 6 years ago

DNS doesn't support segments longer than 63 characters.

@creationix LOL. Almost 64! Thanks for the tip. Base32 encoding of the dat public key makes sense. I'm currently doing a key.substr(0,6) which is nice for readability (looks like the address you entered) and generally pretty unique but base64 is perhaps more guaranteed to be unique?

Side note, what do you use host-dat for?

chrisekelley commented 6 years ago

@creationix - to take RJ's question a tad further, would host-dat be a good candidate to provide multi-dat hosting within bunsen? Right now, bunsen is limited to hosting/sharing one dat at a time.

I just created a new issue for the multi-dat feature if you'd like to discuss it there: https://github.com/bunsenbrowser/bunsen/issues/40

creationix commented 6 years ago

host-dat was just an experiment. I never finished it. But you're welcome to reuse any code that's useful.

chrisekelley commented 6 years ago

@rjsteinert - now that we are using dat-gateway, shall I go ahead and merge your PR https://github.com/pfrazee/dat-gateway/pull/6/files into my dat-gateway fork?

rjcorwin commented 6 years ago

@chrisekelley Let's wait to find out if we can't get the base32 type subdomains working like @RangerMauve has proposed for dat-gateway.

chrisekelley commented 6 years ago

@rjsteinert Sounds good - I just asked @RangerMauve to commit the CORS support and websocket addition from my latest PR and mentioned we'll head down the base32 route. https://github.com/RangerMauve/dat-gateway/pull/1#issuecomment-381938391

RangerMauve commented 6 years ago

Merged in! And now in my master branch. :D Gonna work on making dat-archive-web more pluggable and update my demo to reflect how to use it.

RangerMauve commented 6 years ago

Is anybody working on the b32 thing or can I have a crack at it?

chrisekelley commented 6 years ago

Please @RangerMauve , go for it!

RangerMauve commented 6 years ago

I'm planning on doing the following:

That way applications won't have to worry about doing the b32 conversion, it'll all be handled by the gateway through redirects.

rjcorwin commented 6 years ago

@RangerMauve Let us know the branch you'd recommend and we'll give it a try. I think there will need to be some adjustment to algorithm for the transformation of the dat URLs to gateway URLs but it won't be hard as soon as I have your updated gateway up and running.

RangerMauve commented 6 years ago

I think I have all my stuff merged into the latest master Branch

RangerMauve commented 6 years ago

You can enable the redirect using node bin.js -r

rjcorwin commented 6 years ago

Aha! -r ftw! And yup, it looks like I have a tweak to make to the bunsen code to support the new url structure. screen shot 2018-04-23 at 10 08 06 am

I'll get this on the rails tonight after work.

rjcorwin commented 6 years ago

@chrisekelley I bet we have @RangerMauve's most recent gateway code in Beta2 already, we just need to tweak our custom bin.js. I'll attempt to make the UI backwards compatible to the two different URL schemes so we don't end up putting beta2 folks in a strange limbo when we update dat://bunsen.hashbase.io

RangerMauve commented 6 years ago

Just curious, what did you do that would make the redirecting incompatible? AFAIK the redirect shouldn't affect an iframe's SRC or anything of the such.

rjcorwin commented 6 years ago

When you enter a dat URL in the URL bar, it rewrites it ...

let gatewayFragment = address.replace('dat://', '').replace('/', '')
this.$.view.contentWindow.location = `${window.location.protocol}//${window.location.host}/${gatewayFragment}/`

The first URL you enter will work. Let's say you end up at http://kr612gk1ra51fmj68173qtn3xjt9nfpdr8xkeez0vjykzj6cdq3g.lvh.me:3000/. Then the second URL is the problem because you end up at http://kr612gk1ra51fmj68173qtn3xjt9nfpdr8xkeez0vjykzj6cdq3g.lvh.me:3000/new-dat-uuid/ which will print new-dat-uuid to the screen over and over :-). That second URL should be rewritten to http://lvh.me:3000/new-dat-uuid/, the key being excluding that subdomain.

RangerMauve commented 6 years ago

Thanks for the explanation. :D

I've been hardcoding gateway URLs so I haven't run into this issue.

rjcorwin commented 6 years ago

Yaaaay! Security FTW and not to mention most sites no longer breaking because they expect to be served up at the root of the domain!

screen shot 2018-04-24 at 9 20 00 am

Changes here -> https://github.com/bunsenbrowser/bunsen-ui/commit/bcd4b6321fcfad0e0b438b07c076549f18c5eaab

Not yet published to production but it's published to a dev archive and can be seen at http://gateway.mauve.moe:3000/dev-bunsen.hashbase.io/

It's best browsed in Firefox, make sure to click "Add Application" to allow it to handle dat links.

rjcorwin commented 6 years ago

Got it! Support for with subdomain and without. Thanks to @RangerMauve for the tip on checking for base32 length subdomain, ended up having to do that as well otherwise IP addresses/domains/web-burgers would get nom nom nom'ed.

@RangerMauve @chrisekelley Could you shake those two a bit to see if you find any glaring issues? Then I'll publish to dat://bunsen.hashbase.io

RangerMauve commented 6 years ago

You can't have subdomains on an IP address. You're going to need to put 104.236.57.117 in a hostname. (Add a DNS entry for the top level domains and an entry with a wildcard subdomain entry).

I can give you a mauve.moe subdomain if you want.

rjcorwin commented 6 years ago

@RangerMauve No worries. The IP address example is intentionally one with no subdomain support. Maintaining support for dat-gateway instances without subdomain support is important while our beta2 using a dat-gateway without subdomain support migrate to the impending beta3 with subdomain support. Just a little backwards compatibility for a bit and then we'll take it out. It's the joys/troubles of having the UI update seperately from the gateway.

chrisekelley commented 6 years ago

@rjsteinert - I created an APK with dev-bunsen.hashbase.io substituted for bunsen.hashbase.io. In app.component.ts:

bunsenAddress = "dev-bunsen.hashbase.io/"

APK is s here: https://drive.google.com/file/d/1_mrBi4IefFA9IyAHiF67F6Rizt77a5xP/view?usp=sharing

Whenever I click a dat:// link, it only displays home-bunsen.hashbase.io

The subdomain part is working - I can see http://k2mbe...localhost:3000 in the Application tab:

bunsenapp-debug

We're close!

Also, note that there is a list of datSites, each one having an address property. Would be nice to change that property to url, and have a uuid property once we get that sorted out. then we can really do the peers listing for-reals.

rjcorwin commented 6 years ago

Thanks @chrisekelley - Sounds like that "unable to change actual src URL for iframe" issue again. I'll be able to debug thanks to the dev APK you made. Doing that now.

rjcorwin commented 6 years ago

Alrighty! That dev APK that @chrisekelley published, give it a try! I was thrown for a loop thinking it was not working until I realized Paul's blog brings to light an unrelated but still important issue. He has blog posts like /blog/blog-post-1.html but links to them like <a href="/blog/blog-post-1">Blog Post 1</a> which apparently in all major browsers resolves correctly to /blog/blog-post-1.html.

rjcorwin commented 6 years ago

*all major browser is not quite right, I think it might be a server thing that where servers when requested for a file with no extension assumes it's an html extension. I think this would need to be implemented on the dat-gateway level.

RangerMauve commented 6 years ago

dat-gateway relies on the page loading logic from hyperdrive-http. I think that would be the proper place to get the change.

chrisekelley commented 6 years ago

hey @rjsteinert , you did it! It is working fine. When I switch dats, the urls in Local Storage change as well. Extra bonus - whatever you did has made Paul Frazee's pic now display on his blog!

update: unfortunately, links to sub-pages are not displaying. Must be the append .html when you get a slash feature. (this is an edge-case feature to me. When you hit dir/, most servers usually serves up dir/index.html. )

Following up on @RangerMauve 's pointer to hyperdrive-http: maybe we can override ondirectory:

function ondirectory (archive, name, req, res, opts) {
  archive.stat(name + 'index.html', function (err) {
    if (err) return ondirectoryindex(archive, name, req, res, opts)
    onfile(archive, name + 'index.html', req, res)
  })
}

it is called like this:

var server = http.createServer(serve(archive, {exposeHeaders: true, live: true, ondirectory: newOndirectory}))

Or another option - create a var to handle the default index page, maybe use the same var as Apache httpd:

DirectoryIndex home.php

...but.... I think it's gotta be a function, cause you need to do some filename manipulation.

rjcorwin commented 6 years ago

dat-gateway relies on the page loading logic from hyperdrive-http. I think that would be the proper place to get the change.

Good to know @RangerMauve, I'll file an issue later over there.

Extra bonus - whatever you did has made Paul Frazee's pic now display on his blog!

@chrisekelley This is the magic of putting the dat archives at the root of the domain. Most sites don't expect to be put in a subfolder so they start paths to things like js css images etc with a slash, ie. /pic.png.

rjcorwin commented 6 years ago

Issue filed /foo/ does not serve '/foo/index.html,/foodoes not serve/foo.html` #43

rjcorwin commented 6 years ago

Closing this. All wrapped up. Thanks so much @RangerMauve!