Digital signing authentication per RPC request

1,610 views
Skip to first unread message

some...@gmail.com

unread,
Dec 8, 2015, 1:09:04 PM12/8/15
to grpc.io
Hello,

I have a use case for the gRPC framework but I can't figure out a good way to implement the type of authentication I require. I see examples using TLS for server-side authentication and encryption, and basic examples on how to use metadata for oauth2 or simple authentication, but what I would like is a way to stick a digital signature into a metadata property on each RPC request, signing the payload itself. 

The idea comes from this research article posted by Google on how I can access local resources on my corporate network from an AppEngine application, using digital signatures to verify the request came from an approved source. Basically, I'd like to create a Credential (I'm using grpc-go, FYI) that I can just plug into my service on both sides to stick in the signature + keyname + public key URL into the metadata so that on my server side I can read this information, verify the public key is my list of allowed signers, and verify the signature. I'm not looking for something built out by the library, but I can't build this out myself as I can't seem to get access to the proto payload from the interfaces/APIs provided to me. 

I'd like to have this as pluggable as a Credential, not as a per-message responsibility (e.g. form some sort of header from the components in the message to be signed and verified). Is there something I'm overlooking here or perhaps a different approach to achieve the same level of authentication? 

Any help/advice would be much appreciated!

Thank you,
Prateek M.

Eric Anderson

unread,
Dec 8, 2015, 2:13:31 PM12/8/15
to some...@gmail.com, grpc.io
On Tue, Dec 8, 2015 at 10:09 AM, <some...@gmail.com> wrote:
what I would like is a way to stick a digital signature into a metadata property on each RPC request, signing the payload itself.

That's basically a per-message HMAC, which is used pretty common with vanilla HTTP (no TLS).

On the web, usage of HMACs has diminished in favor of using HTTPS and providing a security token. The security token is different in that it authenticates the client but doesn't ensure the message was sent by the client—but HTTPS prevents tampering.

Security tokens are much easier to implement and don't have issues with whether headers should be authenticated. Header-based HMACs are also incompatible with gRPC streaming. So gRPC hasn't been planning on supporting HMACs and instead suggests using the simpler security tokens. If the network may be hostile, then use TLS.

If you still feel the need for HMACs, then make them part of your messages.

some...@gmail.com

unread,
Dec 8, 2015, 2:48:45 PM12/8/15
to grpc.io, some...@gmail.com
Thank you, Eric. Well put and easy/clear to understand!

I guess it was my naive understanding of "defense-in-depth" that I tried to add additional layers of authentication on top of TLS with a digital signature. Is there no real benefit to a HMAC + TLS vs something like a JWT + TLS? In today's world, using TLS is a no-brainer, but that only covers the server-side part of it all, client/user authentication is still something I want to make sure I get right. I believe having a HMAC would prevent someone from making anything other than replay requests (which I can guard against using a nonce), but a stolen token would enable an attacker to form any sort of request on behalf of that user! I understand that the likelihood of being able to read the message/token when transporting via TLS is unlikely, but as there are vulnerabilities uncovered time and time again, layering my protection seems like a good approach.

I think I've thought up of a way to get this working (in the Go library at least):

Create a general message proto that includes your basic JWT headers (e.g. exp, jti, nbf, etc.) and make it a property on all messages used for requests to the RPC service. When creating a request, store this common message type into the context.Context used to send the request so that a pluggable Credential implementation can pull the information from the context.Context and create a JWT metadata header out of it. Server side, you'd verify the JWT headers match what's in the request and verify the JWT signature. I think this would achieve the same level of protection, as long as the implementation of the nonce is done properly.

Thank you for the information!

Prateek M.

Louis Ryan

unread,
Dec 8, 2015, 3:38:14 PM12/8/15
to some...@gmail.com, grpc.io
On Tue, Dec 8, 2015 at 11:48 AM, <some...@gmail.com> wrote:
Thank you, Eric. Well put and easy/clear to understand!

I guess it was my naive understanding of "defense-in-depth" that I tried to add additional layers of authentication on top of TLS with a digital signature. Is there no real benefit to a HMAC + TLS vs something like a JWT + TLS? In today's world, using TLS is a no-brainer, but that only covers the server-side part of it all, client/user authentication is still something I want to make sure I get right.

Have you consider using client-certs?

 
I believe having a HMAC would prevent someone from making anything other than replay requests (which I can guard against using a nonce), but a stolen token would enable an attacker to form any sort of request on behalf of that user!

Not any sort of request, you can use audience "aud" claim to restrict the allowed set of operations. You should also not be minting JWTs with highly extended expiration. With those safeguards in place you're already quite well protected. A strict nonce would also mean an attacker would have to be able to get the token before it was received by a server, now were talking TLS MITM or an exploit on the client, both of which are probably worse than any replay scenario.
 
I understand that the likelihood of being able to read the message/token when transporting via TLS is unlikely, but as there are vulnerabilities uncovered time and time again, layering my protection seems like a good approach.

I think I've thought up of a way to get this working (in the Go library at least):

Create a general message proto that includes your basic JWT headers (e.g. exp, jti, nbf, etc.) and make it a property on all messages used for requests to the RPC service. When creating a request, store this common message type into the context.Context used to send the request so that a pluggable Credential implementation can pull the information from the context.Context and create a JWT metadata header out of it. Server side, you'd verify the JWT headers match what's in the request and verify the JWT signature. I think this would achieve the same level of protection, as long as the implementation of the nonce is done properly.


 

Thank you for the information!

Prateek M.

--
You received this message because you are subscribed to the Google Groups "grpc.io" group.
To unsubscribe from this group and stop receiving emails from it, send an email to grpc-io+u...@googlegroups.com.
To post to this group, send email to grp...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/grpc-io/a3674b9e-8224-489e-9f6d-dda9e72227ba%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Prateek Malhotra

unread,
Dec 9, 2015, 10:03:05 AM12/9/15
to Louis Ryan, grpc.io
Can you elaborate a bit on client certs? Would I package a key/cert with my client to establish a TLS connection? GAE already provides a secure way to digitally sign blobs for your app without giving any access to the private key and it also rotates the keys for you. IMHO, the less key management I'm charged with as a developer, the better!

You're right, an aud, strict JTI, and short exp would help and was something I was already planning on. My idea given previously is no better than just using a proper nonce on the JWT header to begin with so no need to include the header in the message.

I believe a MITM attack would be mitigated with a HMAC signature, but I guess the only way to get this would be to include it as part of the RPC message as it sounds like it won't be something supported by the auth mechanisms provided by grpc. I'll either have to have faith in TLS or bake in a HMAC signature myself; the latter being a paranoid, layered approach. As I'm also using grpc-go I need to keep in mind that it's TLS implementation hasn't had the same time to marinate as other TLS implementations have.

Thank you for the input!

Prateek M.

Louis Ryan

unread,
Dec 9, 2015, 1:34:37 PM12/9/15
to Prateek Malhotra, grpc.io
On Wed, Dec 9, 2015 at 7:02 AM, Prateek Malhotra <some...@gmail.com> wrote:
Can you elaborate a bit on client certs? Would I package a key/cert with my client to establish a TLS connection?
Yes
 
 GAE already provides a secure way to digitally sign blobs for your app without giving any access to the private key and it also rotates the keys for you. IMHO, the less key management I'm charged with as a developer, the better!

If you're going to use AE then I would just stick with what it gives you 

You're right, an aud, strict JTI, and short exp would help and was something I was already planning on. My idea given previously is no better than just using a proper nonce on the JWT header to begin with so no need to include the header in the message.

I believe a MITM attack would be mitigated with a HMAC signature,

Only helps when the attacker is also injecting, observing attackers are still really bad so the difference between the two depends on what your service is doing.
 
but I guess the only way to get this would be to include it as part of the RPC message as it sounds like it won't be something supported by the auth mechanisms provided by grpc. I'll either have to have faith in TLS or bake in a HMAC signature myself; the latter being a paranoid, layered approach. As I'm also using grpc-go I need to keep in mind that it's TLS implementation hasn't had the same time to marinate as other TLS implementations have.

true, but its also leaner than OpenSSL in terms of features and code (just like BoringSSL and NanoTLS) which has is't pros....
Reply all
Reply to author
Forward
0 new messages