Giter Site home page Giter Site logo

httpsig's Introduction

httpsig

Standards-based HTTP request signing and verification for Go

Go Reference Alpha Quality Build Status BSD license codecov Go Report Card


Introduction

httpsig provides support for signing and verifying HTTP requests according to the HTTP Message Signatures draft standard. This standard focuses on signing headers and request paths, and you probably want to sign the request body too, so body digest calculation according to Digest Headers is included.

Signed HTTP requests are ideal for scenarios like sending webhooks, allowing recievers to securely verify the request came from your server, mitigate replay attacks, etc.

Contrary to the commonly-used x-hub-signature, The standards implemented by this package provide a signature of the entire request, including HTTP headers and the request path.

Usage

Signing HTTP Requests in Clients

To sign HTTP requests from a client, wrap an http.Client's transport with NewSignTransport:

client := http.Client{
	// Wrap the transport:
	Transport: httpsig.NewSignTransport(http.DefaultTransport,
		httpsig.WithSignEcdsaP256Sha256("key1", privKey)),
}

var buf bytes.Buffer

// construct body, etc
// ...

resp, err := client.Post("https://some-url.com", "application/json", &buf)
if err != nil {
	return
}
defer resp.Body.Close()

// ...

Verifying HTTP Requests in Servers

To verify HTTP requests on the server, wrap the http.Handlers you wish to protect with NewVerifyMiddleware. NewVerifyMiddleware returns the wrapping func, so you can reuse configuration across multiple handlers.

h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain")
	io.WriteString(w, "Your request has an valid signature!")
})

middleware := httpsig.NewVerifyMiddleware(httpsig.WithVerifyEcdsaP256Sha256("key1", pubkey))
http.Handle("/", middleware(h))

For more usage examples and documentation, see the godoc refernce

The Big Feature Matrix

This implementation is based on version 06 of HTTP Message Signatures (draft-ietf-htttpbis-message-signatures-05 from 8 June 2021). Digest computation is based on version 05 of Digest Headers (draft-ietf-httpbis-digest-headers-05 from 13 April 2021).

Feature Notes
sign requests
verify requests
sign responses
verify responses
add expires to signature sorely needed
enforce expires in verify
@method component
@authority component
@scheme component
@target-uri component
@request-target component Semantics changed in draft-06, no longer recommented for use.
@path component
@query component Encoding handling is missing.
@query-params component
@status component
request-response binding
Accept-Signature header
create multiple signatures
verify from multiple signatures
rsa-pss-sha512
rsa-v1_5-sha256
hmac-sha256
ecdsa-p256-sha256
custom signature formats eddsa is not part of the spec, so custom support here would be nice!
JSON Web Signatures JWS doesn't support any additional algs, but it is part of the spec
Signature-Input as trailer Trailers can be dropped. accept for verification only.
Signature as trailer Trailers can be dropped. accept for verification only.
request digests
response digests Tricky to support for signature use according to the spec
multiple digests
digest: sha-256
digest: sha-512
digest: md5 Deprecated in the spec. Unlikely to be supported.
digest: sha Deprecated in the spec. Unlikely to be supported.
digest: unixsum
digest: unixcksum
digest: id-sha-512
digest: id-sha-256 id-* digests are more resilient for content-encoding support
custom digest formats

Contributing

I would love your help!

httpsig is still a work in progress. You can help by:

  • Opening a pull request to resolve an open issue.
  • Adding a feature or enhancement of your own! If it might be big, please open an issue first so we can discuss it.
  • Improving this README or adding other documentation to httpsig.
  • Letting me know if you're using httpsig.

Links

httpsig's People

Contributors

dependabot[bot] avatar jbowes avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

httpsig's Issues

Body length 0 error with basic example

Hello,

Trying out the library I looked at the example in the README and came up with this as a basic example for using a POST request:

package main

import (
	"bytes"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"

	"github.com/jbowes/httpsig"
)

func main() {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Printf("%#v\n", r.Header)
		body, _ := io.ReadAll(r.Body)
		fmt.Fprintf(w, "Hello, client: %s", body)
	}))
	defer ts.Close()

	privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		log.Fatal(err)
	}

	//client := http.Client{}
	client := http.Client{
		// Wrap the transport:
		Transport: httpsig.NewSignTransport(http.DefaultTransport,
			httpsig.WithSignEcdsaP256Sha256("key1", privKey)),
	}

	data := map[string]string{
		"hello": "world",
	}

	b, err := json.Marshal(data)
	if err != nil {
		log.Fatal(err)
	}

	buf := bytes.NewReader(b)

	resp, err := client.Post(ts.URL, "application/json", buf)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(string(body))
}

Trying to run this results in the following output:

go run .
2023/10/23 23:21:20 Post "http://127.0.0.1:55020": http: ContentLength=17 with Body length 0
exit status 1

I think the problem is that

r.Body = io.NopCloser(bytes.NewReader(b.Bytes()))
... should be setting nr.Body, not r.Body. I think the reason for this is the function returns transport.RoundTrip(nr) which at that point holds a reference to the original (and at that point consumed) r.Body.

Option to use newer Content-Digest field with sha-512

The changelog for draft-ietf-httpbis-digest-headers states:

Since draft-ietf-httpbis-digest-headers-07

   *  Introduced Repr-Digest and Want-Repr-Digest, and deprecated Digest
      and Want-Digest.  Use of Structured Fields. #1993, #1919

...

Since draft-ietf-httpbis-digest-headers-05

   ...

   *  Add Content-Digest #1542

Libraries for other languages are using the newer Content-Digest header field:

Content-Digest: sha256=:abc:,sha512=:def:

Would be nice if there was a way to do this here as well, and to select sha512 as the algorithm.

feature proposal

hellow @jbowes,

For my own uses, I have experimented with a change which I'd like to know if you're interested in before I spend more time on it for a proper PR.

Long story short, whenever you want to add support for a specific elliptic curve and a specific hasher function, you are forced to implement a specific private signer & verifier, as well as a specific public signer & verifier functions (ie: signEcdsaP256Sha256, verifyEcdsaP256Sha256, WithSignEcdsaP256Sha256, WithVerifyEcdsaP256Sha256).

I implemented WithSignEcdsa(), WithVerifyEcdsa, signEcdsa & verifyEcdsa which take an additional crypto.Hash parameter and use key.Curve.Params().Name and crypto.Hash.String() to infer the algorithm. With this, I could easily switch between curves and hash functions to support combinations that are currently unsupported in your package.

Is this something you'd be interested in ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.