diff --git a/README.md b/README.md index fb8f743..5687a2a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,69 @@ # sig-auth -Signature authentication service designed to be used as middleware for a reverse proxy +Signature authentication service designed to be used as middleware for Caddy. + +# About + +This project was created to test an idea I had to use [RFC9421: HTTP message signatures](https://www.rfc-editor.org/rfc/rfc9421.html) for authentication. The way it works is simple. + +1. The user registers a public key, and the server sends a key ID back +2. The user signs the HTTP request with their private key, passing in the key ID +3. The server verifies the signature and returns a response with the user ID in a header + +Use this as middleware for a reverse proxy, and HTTP message signatures can be used to identify the user without any shared secrets. It could even be adapted, with some configuration changes, to use an API key without revealing it to the user. + +I also created this project as a way to learn Go. Although I'm satisfied with the results, it likely doesn't follow a lot of expected conventions. + +It is built around the [httpsig](https://github.com/common-fate/httpsig) library. This is the only library I found that implements the final RFC. Other libraries implement older drafts. + +# Try it out + +If you use Nix shell, there is a `shell.nix` config in the repo that should give you a working environment for running the project. If you can't/don't want to use Nix then the only requirements are Go and Caddy. (And possibly gcc. Is it safe to assume you'll have that?) + +One program runs both the server and a test client. + +Run these commands in separate teminals to run the authentication server and a reverse proxy: + +``` +go run . -db register.db +caddy run --config test_assets/Caddyfile +``` + +Then run these commands to register a key and make an authenticated request with it: + +``` +go run . -r -key test_assets/ed25519.pub -user test_user -base-url http://localhost:8080 +# Copy the key ID returned +go run . -c -key test_assets/ed25519 -id +``` + +If all is well you'll see the signing info on both client and server, see no errors, and get a response of "Hello, test_user" + +# Live use? + +This code is not ready for live use. + +I do not have much experience with crypto. Although I've tried to avoid mixing things and "rolling my own", I do not have the ability to evaluate and guarantee the safety of my code. + +These things would also need to be updated for me to be confident using it on a live server: + +There should be other database options besides sqlite. + +The registration flow needs better protection. The registration endpoint should not be open. The user should be authenticated through external means before trusting the key. Alternatively, with support for other databases, have the downstream service add keys to the database. + +The authority should be a configuration option, but I'm not likely to add that due to other restrictions that make this not work as general purpose middleware. + +The httpsig library isn't designed for this use. There are a few things that I think would have to be changed to make it fully functional. + +1. There should be support for dynamic tags, which would be passed to the KeyDirectory. + 1. This would be so the middleware could sit in front of multiple applications, each using its own tag. +2. It should be possible to allow multiple authorities. +3. If `content-digest` is in the covered components, there should be an option to use the `Content-Digest` header instead of recalcuating the digest itself. + 1. In a middleware scenario, the authentication service doesn't have access to the body, so the calculated digest will be wrong. + 2. Digest validation can be handled downstream. + +I also think the behavior of the `ForbidClientSideAlg` flag should be different, or there should be another option. If the flag is set, the verifier rejects signatures that include an algorithm. There should be an option where the client side algorithm is simply untrusted. In this mode: + +4. The server must know the key algorithm through some other means. This project saves the algorithm with the key during registration. +5. If present, the client side algorithm is still compared to the known algorithm, as required by the RFC. +6. If not present, it doesn't matter.