imagej / imagej-server

A RESTful web server for ImageJ [EXPERIMENTAL]
Apache License 2.0
39 stars 17 forks source link

Enable security (optimally by default) #16

Open joshmoore opened 6 years ago

joshmoore commented 6 years ago

Thinking of the almost running gag of "Default security settings" of various servers (mongo, etc), I'd suggest that the default settings of imagej-server provide at least some basic security. Things to consider:

joshmoore commented 6 years ago

Perhaps a place to start? http://www.dropwizard.io/1.0.3/docs/manual/auth.html

turekg commented 5 years ago

Depending on the use case I can see a the following ways to proceed on this: 1) The simplest option: user has the option to download a war file which he can deploy to own servlet container/app server, letting the container manage security (SSL and authentication). Pros: little work on our part, except to provide a war file without jetty Cons: user must have own servlet container. No fine tuning of access rights beyond accessing the app. 2) Embedded jetty is configured to only listen to localhost (no SSL and no authentication) Pros: minimal work on our part to implement jetty config. Cons: User is stuck with that option 3) App is packaged with a servlet container (like the Knime Server) with instructions on how to set up SSL and authentication Pros: not too much work in order to create installer, instructions Cons: user needs to do a little bit more work at installation time, no fine tuning of access rights beyond accessing the app. 4) Authentication is built into the app (Dropwizard option) permitting finer grade access rights Pros: User is able to decide who has access to what data. Note that this solution provides data security, not network security, which still has to be provided by the container (SSL) Cons: A much bigger effort on our part and still need to address SSL issue (so do we're back looking at 1) or 3) as solution to that. What are the requirements? is container managed SSL + authentication the most pressing right now? What is the use case for 4)?

ctrueden commented 5 years ago

What are the requirements?

From my POV, the main requirement is that it needs to be possible to spin up a "quick server" and connect to it from another process, in a secure fashion. For example, @kephale wrote a plugin for Atom that lets you execute ImageJ scripts from the Atom editor, using a running ImageJ. This is a powerful way to hook up additional tools to ImageJ. But it would be unfortunate if every tool that hooked up this way needed the ImageJ server to be wide open to incoming connections from everywhere. There needs to be some authentication, secret token, or similar in order to restrict who can boss ImageJ around.

I am not an expert on these technologies, but based on my understanding, requiring end users to run their own servlet container or app server seems like a no-go. The Atom plugin mentioned above is currently easy to get working with a standard installation of ImageJ with Server update site enabled. The addition of authentication needs to present minimal additional barriers to intended usage, while preventing unintended/malicious usage.

Regarding SSL over localhost:

  1. Is it necessary, security-wise? I am clueless here.
  2. If it is necessary, does this help? https://letsencrypt.org/docs/certificates-for-localhost/
  3. If Let's Encrypt is not OK for some reason, what about a self-signed cert?
turekg commented 5 years ago

Security is not an issue (in principle) if you are connecting to the server on the same host. We could enforce this in the distro by configuring jetty to only allow connections from localhost. This would take care of "malicious" connections from anywhere else. But I suspect the issue is really for those people who want to set up BigDataServer on one machine and access it from somewhere else. In that case, we could configure jetty to only listen to the SSL port and to keep configuration at a minimum, expect an SSL certificate with a well defined name in a well defined location (which would depend on the OS, unfortunately). Alternatively, we could write a deploy script that either

This is the path of least resistance IMO.

If additionally some users also want to implement user authentication to further restrict access, then my recommendation is to go with option 1) or 3) above

oeway commented 5 years ago

Hi, thanks for pointing this out, I started to look into this because I am working on a ImJoy(https://imjoy.io) plugin for ImageJ.

For me, I tend to think there is a serious security risk by not enabling security.

I have been testing it inside my network that basically anyone inside network can execute any FIJI modules on my computer. I imagine it can be even worse if my computer is not behind a firewall or router.

If we run the web server only on 127.0.0.1 (the loopback address, but not localhost), as proposed by @turek, it will cut the access from other hosts. However, it's still not secured, because the connection can still come from a random page opened in the user's browser for example WITHOUT even noticed by the user. You can try this from this ImJoy client: https://imjoy.io/lite?plugin=oeway/ImJoy-Plugins:ImageJClient I haven't try enough, but it may be possible that I can easily scan the user's disk and read files through one of the FIJI module.

To be constructive, I think we should at least enable a basic token authentication and enable that by default. For simplicity, I suggest to use HTTP Basic which means token will be required to access all the apis.

  1. a randomly generated token will be displayed with a dialog to the user, printed to the console, or the token can be specified by ImageJ --server --token=xxxxxx.
  2. The token will be provided from the client, either added to the HTTP request header (Authorization: xxxxxxxxx) or as a URL parameter (http://localhost:8080/objects/...?token=xxxxxxxx).

To further bring down the risk, there should be some indication on the imagej interface that the server is running, because people may simply forget to turn it off. For that, I would suggest to make a control panel for the server, showing the current client connections, and importantly when the user close the panel the server turns off.

HTTPS is a different thing here, it encrypt the communication, even if we have https, we still need the authentication. On the one hand, HTTPS is a nice addition because nowadays many HTML5 features can only be used in HTTPS connection. For example, in ImJoy, we enforce HTTPS by default so we can support PWA and run the web app offline, and that's also required if we want to access the camera from the web app; On the other hand, it's hard to enable HTTPS from ImageJ, because that will require significant amount of work to set it up and I agree with @ctrueden that that's a no go zone. We are facing the same issue in ImJoy, since we have the plugin engine (python) which starts a web server and connect with the web app. The recommended solution for this is to use an existing tunneling service such as ngrok or Telebit(recommended) which basically wrap a http service into https and expose it to the internet. For server side deployment, SSL can be easily handed by NGINX for example, there is no need to handle this in the app-level.

Overall, I think the authentication should be prioritised and enabled by default as soon as possible due to the potential risk. Also see the vulnerability in Zoom reported recently, this is somewhat similar.

ctrueden commented 5 years ago

@oeway Thank you for the detailed analysis! Very helpful.

Unfortunately, I do not currently have the bandwidth to work on this project. Maybe someone at CSBD does? (CC @frauzufall @turekg @maarzt @tpietzsch @fjug)

Otherwise, as always, pull requests are warmly welcome.