Protecting the private key in a compiled application

Hi there,

We’ve built a prototype of Riff.CC using Ceramic and ComposeDB, which uses it to store IPFS pin data. We’re doing so via a private key which is associated with a DID which is added as an admin on the Ceramic node. Then access controls are implemented using Ethereum accounts.

We’re hoping to avoid exposing the private key to the user, so that they cannot get around the Ethereum access controls. Right now that looks like deploying on Vercel with encrypted environment vars, but that feels a bit like an ugly hack.

Instructions are here for the Ceramic node we’re running - GitHub - riffcc/ceramic-node
and here for the web application we’re running - GitHub - riffcc/ceramic-riff-web: Riff.CC, implemented using ComposeDB and Ceramic.

Are we using ComposeDB wrong? :sweat_smile:

2 Likes

I’m commenting here to follow the thread, to make sure we do it correctly as well :slight_smile:

Without knowing how your app works, will the client UI load code that uses these environment variables? If so I don’t believe the encryption helps you out, the encryption only protect them from being plain-text in server build logs (I think). The client user could set breakpoints in the browser and view environment variables which are part of any code that is served up to the client/browser.

At least for WalletChat, whenever we run into this we use our own API to act as middleware between the client and servers, to protect any private keys such as this, or paid API tokens we know a client could steal/re-use if they inspected our client code.

In Ceramic (and therefore ComposeDB) DIDs control streams so there’s no built-in way to do access control with Ethereum.

If you want create specific control mechanisms, you can do so by having your service control streams and allow your users to interact with them based on your access control logic, but that means your users can’t “own” the streams, at least when it comes to Ceramic’s logic.
Fundamentally you can’t at the same time have your users control their streams and restrict them with your own logic, it has to be one or the other.

Regarding your private keys in particular, it’s something only your server should have access to, not your client and end-users in any case.

1 Like

Hi Paul, thanks for the reply!

We’re building a platform where users can submit uploads (an ipfs hash and some metadata), and then moderators can approve or reject those uploads to allow or prevent them from appearing on the front page. We’d also like for moderators to be able to make minor edits to descriptions and the like.

Would an alternate approach be to allow the users to control their own streams, then have the website control its own stream?

In this hypothetical, the website could maintain a list of what’s approved and not approved, and only allow Eth admins access to change that stream. It could also maintain a list of edits to the content.

Is there some way to “partially override” the contents of a stream by taking changes from a different stream, and render it?

Regarding your private keys in particular, it’s something only your server should have access to, not your client and end-users in any case.

Agreed. As implemented I haven’t been able to confirm for sure that the keys are exposed to the user, but I’m fairly certain they are.

1 Like

Yes from what you describe it seems like there isn’t a high need for your users to control their submissions, mainly there doesn’t seem to be a need to update them after they are created, is there?

Considering you also want moderators to possibly change the contents, these streams will have to be controlled by your app anyways, so the simplest solution is probably to create them directly in your app’s backend.

It may seem silly, but we really want to do it as described - particularly because we want users to be able to submit their uploads to sites running the same software that aren’t our own.

Our hope is we could just track the difference between a users submission and our view of it somehow. Particularly because we want to run a service that scales effortlessly, and if we control all the streams that seems a lot harder to do past a certain point.

1 Like

For sure you can implement different solutions based on your needs, for example you can use relations to point to “curated” streams that are not controlled by your app.

1 Like

hey wings, welcome to the forum - looks like this one is resolved but let me know if you have unanswered questions!

also, excited to see what you build - we have a channel for sharing your project Ceramic and also a grants program

Hi avi!

We haven’t quite worked out how to do this yet and are still working out the details.

@paul could you describe your suggestion in a little more detail? That sounds like roughly what we want to do.

Essentially, this is what I have as a rough redesign goal (I’ve put ? around things I’m not sure about)

  • users would be able to use 3ID Connect to sign in with Ethereum, Filecoin wallets
  • they could then upload a submission/release by uploading the files to IPFS themselves (and getting an IPFS CID) or uploading via Estuary.tech
  • and filling out an upload form with the details of their upload
  • when they submit the upload, it gets stored in their own stream immutably using their keys, giving them control of their content. At the same time, their browser would send a request to our lightweight Node.JS server, informing the server that their DID’s stream has uploads in it
  • Our server would see the upload by that user and upon approval of it by a moderator, create a relation(?) that adds the upload to a curated stream(?), allowing end users to list all the content of all users minus any abusive content.

As a bonus, we would like to be able to do mutations(?) against arbitrary user streams without modifying the underlying user stream (as, well, we can’t :wink: We don’t have the keys!) somehow, and display the result of the user stream + our modification to it.

The use case - imagine a streaming platform (a la Netflix, Spotify) with primarily Creative Commons content, where an artist or fan can upload eligible media to the site easily and then the operators of the site can approve/reject content easily. The twist is that we want multiple streaming platforms to be able to run independently, and share content with each other trustlessly, essentially saying “your curated stream is something I trust, so I will show it to my users”. This would take the form of a simple publish/subscribe system - Site A decides they trusts site B’s content, so they subscribe to Site B, and suddenly Site A has everything it had plus Site B’s content. Site B sees this happen, and decides Site A is neat too, so subscribes back. As a result, both Site A and B have now benefited from each other’s content set.

Graph databases seem like a natural fit for this sort of project.

I don’t have more details as I haven’t implemented such system yet, just pointing out the fact that you can create relations to streams you don’t control so you can create a system of curated streams pointing to user-created ones.
Then you can have the curated streams as the entry-point to list contents in your app for example so it doesn’t display unwanted contents.