This is a nice write-up. I recently added post-to-bluesky support to my ongoing social-media-scheduler project [1], thinking it would be the simplest of the services to work on, but I ended up getting really confused instead.
DID and handle resolution was the easiest part of ATProto---as the author says, a library can do the job easily. For Ruby it's DIDKit [2]. Where ATProto really threw me was the seeming non-ownership of record types. Bluesky uses "app.bsky.feed.post" for its records, as seen in the article; there seem to be a lot of these record types, but there doesn't seem to be a central index of these like there are for DIDs, or a standard way of documenting them... and as far as I've been able to find, there's no standard method of turning an at:// URI into an http:// URL.
When my app makes a post on behalf of a user, Bluesky only sends an at:// URI back, which I have to convert myself into an http:// URL to Bluesky. I can only do that with string manipulation, and only because I know, externally, what format the URL should be in. There's no canonical resolution.
> I have to convert myself into an http:// URL to Bluesky
at:// URIs and specific lexicon are not limited to a single app. The NSID (app.bsky.feed.post) has authority based on domain, but Bluesky cannot prevent anyone from reading / writing records of that type.
There are alternative apps that read the same at:// but put them under a different https://...
tl;dr, there is not a 1-1 mapping between at:// and https://, it's 1-N
Yeah, sorry for the inconvenience. We added a registration requirement to prevent anyone from abusing the free trial so easily, although it would have been a nice idea to have a demo available.
Thank you for saying so. We've put a lot of work into just getting to this state, and next for us comes a lot more work on both features and security, like you said.
Our focus right now is on independent users who are looking for convenience, since we can't expect to fully support larger groups who have extremely high standards that we can't yet meet.
Edit: Apologies, I didn't intend to dismiss rightfully high security expectations as "extremely high standards". To put it another way, we have to start somewhere, and we've put plenty of work already into the basics, but our obvious next steps are to step up on security while also supporting users who are already willing to use Shellvault as-is. My above comment should have said that we don't yet have the resources to properly support enterprise-grade security concerns.
Dismissing such basic security concerns as "extremely high standards" is quite off-putting. You need to earn a very, very high level of trust to successfully run such a service, as the other comments in this thread clearly show, and this comment does the opposite, at least for me.
It is hard to imaging that you interviewed any potential users of such a system before building it. You are solving a problem users do not have in a way that creates problems for users.
Many other commenters have expressed similar misgivings, but I'll respond to this top-rated one so that I don't pollute the thread.
First, thanks for your brutality. It's good to know that a service like this (which deals with such sensitive content) is treated suspiciously at first.
Second, a few commenters have shown that it may be possible to reduce the MitM aspect by pushing more work into the browser with a method that could also provide end to end encryption. We're going to look into this thoroughly because we thought it was impossible at first, but I'm also curious if that would change your mind at all about using the service. At the very least, it would improve our users' security, so we're still going to see if we can do it.
Third, I do want to emphasize that we encourage users to create multiple keys to use, so that they have lots of power over granting and revoking server access via those keys (kind of like a new proxy credit card in your example, I guess). There are lots of ways a service like Shellvault could accidentally encourage poor habits, and we're working very hard to encourage good ones instead.
The truly evil business model would be to offer this as a free service. The company would be set up for a very profitable acquisition just by their placement in their customer's data streams.
I don't think I would call the services problem the "MitM aspect" -- that is literally the largest point of value an ssh connection gives you -- its primary reason for being used is to stop MitM snooping/collection and takeover (of traffic and auth). Like most all of ssh's design is specifically crafted to reduce the risk of MitM. This offerings design basically tosses that out of the window.
* You hand over the keys to the castle (multiple keys or not -- thats irrelevant)
* You specifically route traffic through a midpoint that by all means has access to inspect the traffic. You have to trust both that the operators of the service will not do this AND that there is no compromise of the service with no way to verify.
if you cannot 'see' the commands and passwords etc., then a malicious interuder can also not see it. you need to build it with in mind that you will be owned. if you design it like that, then most of the complaints you have gotten are invalid. it can be that you yourself are trustworthy and good person, but this doesn't say that there might be unknown vulnerabilities in your code or infrastructure. once someone is on the box, they can see the same as you, but they might not be so kind as to drop the information.
The big one is convenience: if you need to do some quick maintenance from a computer you're not usually using, it's fast and easy to do so here (e.g. if you want to administer your server from a firewalled work PC, or from your parents' house).
Our goal is to provide a useful service for anyone who wants to be able to log in from anywhere, which does unfortunately mean we're stuck as a potential MitM. We wrote a lot of documentation about how to mitigate the security issues [1], but ultimately we encourage anyone with security on the mind to use their own SSH client.
Theoretically, yes (see our FAQ [1]), which is why we encourage careful usage. We don't log commands or usage.
We actually looked at a browser-only implementation first. Sadly, there's a limitation on JS SSH: in-browser Javascript can't do SSH, presumably because it lacks the right security code. It needs system-level library support which isn't available except in Chrome's NaCL (which is how Chrome Secure Shell works). The stack you suggested here is a lot like how Shellvault already works, unless I'm missing something -- is there something about this stack that would let us stop being a middleman? It looks to me like the node SSH service would still have to be running somewhere, and our features are designed around being a cloud-only client (there are already lots of good deploy-it-yourself portals that we're not trying to compete with).
"We actually looked at a browser-only implementation first."
That leads me to have two questions:
1. Could you do a browser implementation that doesn't send things to you which connects to a proxy on their client or server machine? As in, something they control handled whatever data your machines are handling.
2. If not or as a supplement, could you do paid, shared-source app they could host in arbitrary machine or VM? As in, they could inspect the product, build it from source, and deploy it to trusted hosts. They pay your company mainly for the convenience and updates.
For 1, we're going to look into it (or something like it). It sounds like the service could be improved a lot if we could implement end-to-end encryption without the MitM dangers.
For 2, those kinds of products already exist, and we're not intending to compete with them (consider Apache Guacamole, linked by another commenter somewhere in the thread).
The point about the system I described is that you wouldn't be seeing any plaintext.
It's a mistake that the ssh client requires node, I didn't know that. There's no fundamental reason you couldn't implement an in-browser ssh client the way I described, it's just more work than doing it the way you've done it.
The fact that the person responding for the site does not understand this instantly (or is able to confer with someone who does before responding) makes it very apparent that there is not nearly enough understanding of ssh to be running any type of service like this.
> in-browser Javascript can't do SSH, presumably because it lacks the right security code.
This makes it sound like you don't exactly have any idea what you're doing, which is worrying for a provider of an ssh client.
Javascript is turing complete so there is no reason in-browser javascript couldn't fully implement the ssh protocol, you "just" might have to write or port the appropriate crypto routines to javascript. And of course, you'd need a http/websocket based tcp proxy since you won't be able to do a raw tcp connection to port 22 in a browser.
(Although I'd be extremely wary of using any non-standard ssh client / crypto library implementation - who knows what timing attacks and side channel info leaks might lurk in a less-vetted implementation than openssh)
>is there something about this stack that would let us stop being a middleman?
Yes if you terminate the connection in the browser and your server just acts as a TCP<->websocket proxy, you can verify the fingerprint and (assuming you trust the JS) be sure the proxy isn't MITMing.
> It looks to me like the node SSH service would still have to be running somewhere
Oh, so by "terminate the connection in the browser", you mean the service would connect via SSH to a server, start a separate socket server connected to a terminal, and then hand off the connection entirely to the browser? If not, could you explain what you mean?
If so, I can see some potential issues, but that's a really nice idea for how this could be improved, and I'll look into it more. Thanks (to you and jstanley both)!
I'm not sure I understand what you mean, but the idea is just that the shellvault server is just a dumb pipe. The only thing it does is translate from tcp to websocket and back. You you have some kind of ssh.js that does everything an ssh client does. The only problem is that the browser can't use direct TCP sockets. So instead of SSHing directly into the server you use a websocket to connect to shellvault, and shellvault forwards the data on a TCP socket to the ssh server. And of course takes the data from the TCP sockets and sends it back to the browser via websocket.
That way shellvault acts as a dumb proxy and only forwards encrypted data packets while all the crypto stuff happens in the browser and the ssh server.
Agreed. But since we’re rewriting the implementation in this comment thread there should be an emphasis on E2E encrypted connections WITH key based auth. SSHy packaged up nicely with a web socket proxy through Shellvault, or any provider for that matter, would be more secure than Shellvault’s current implementation but I think the lack of being able to use key based auth would be a nonstarter for many.
Thanks for the feedback! This is something we've had in mind for a while, and we're hoping to get to work on enterprise support (including other features like key sharing between team users and usage auditing) after solidifying the platform for independent users. It'll be easier to add proxy support, but I agree that a possible opening like that isn't going to cut it.
Another possible option is OAuth integration with cloud platforms like AWS or GCP, which more and more companies (including mine) are starting to use more often -- but they're still a minority compared to internal networks.
Right, Shellvault isn't for everyone: we're aiming to provide a good service for anyone who wants more convenience than normal SSH can provide, and we've worked hard on transparently documenting security considerations and adding features that don't compromise on privacy.
We've done a lot to try and work on trust, but that won't truly come without a good record of contented customers. Hopefully we can work hard and impress you!
Looking good, you're right it's not for everyone but it will be the right solution for some, so don't get discourage from these mostly negative (rightly) comments. I see you comparatively to Serverpilot which is another server management for dummys type of service, they have made themselves a nice niche in the novice website admin community, which is where I see your service succeeding. Having said that one reason for the success of Serverpilot is that the founders had excellent reputation in the dev community as long time Microsofties, but browsing Shellvault I see no information who is behind the service. I have no idea who you are and that's what makes me hesitant about using your service. Some background info would help. BoL.
Thanks a lot for your advice and kindness. We've been hesitant to overuse industry credentials (I work at Google) because I personally look for documentation quality over goodness-by-association, but I agree that we haven't done enough to answer the question of "who is this, and why should I trust them?". You are right that having too little identity does not help the service look better, so we'll take another look at this.
DID and handle resolution was the easiest part of ATProto---as the author says, a library can do the job easily. For Ruby it's DIDKit [2]. Where ATProto really threw me was the seeming non-ownership of record types. Bluesky uses "app.bsky.feed.post" for its records, as seen in the article; there seem to be a lot of these record types, but there doesn't seem to be a central index of these like there are for DIDs, or a standard way of documenting them... and as far as I've been able to find, there's no standard method of turning an at:// URI into an http:// URL.
When my app makes a post on behalf of a user, Bluesky only sends an at:// URI back, which I have to convert myself into an http:// URL to Bluesky. I can only do that with string manipulation, and only because I know, externally, what format the URL should be in. There's no canonical resolution.
[1]: https://toucanpost.com [2]: https://github.com/mackuba/didkit