Getting Mutual SSL Authentication information with Heroku
Asked Answered
G

1

11

I'm looking to build a mutual ssl authentication with Heroku, where a third party calls a Heroku endpoint and the response from Heroku is dependant on which third party calls Heroku. I need to use mutual ssl as the third parties are very security conscious.

I have a third party calling Heroku (via the SSL add-on) with a certificate and am able to get a response. So the mutual SSL handshake appears to have worked.

However my application is unable to determine which third party has called Heroku as there is no certificate information to examine. I've looked at the Heroku headers to see if there is additional information provided by the SSL add on, but could not find anything.

Is there a way to get certificate information from the mutual sal handshake via any other method for Heroku?

Ginnygino answered 15/3, 2013 at 15:5 Comment(2)
I've contacted Heroku. They have let me know that this is simply not possible. Maybe someone still comes up with some solution, but I guess that is unlikely.Intertype
Heroku has informed me that if there's a working solution with ELB, they can probably get it working, too.Intertype
P
7

Heroku SSL is implemented using Amazon Elastic Load Balancers (ELB), which provide SSL termination with your SSL cert in front of Heroku's Routing Mesh.

Because the SSL is terminated and details of the negotiation are not passed through, there is no way for you to get certificate information from the mutual SSL handshake.

However, if your goal is to use certificate based authentication to authenticate the HTTP client, you can build that in at the application layer.

Disclaimer: I am not a cryptographer and you should consult with one before authoring any crypto-based authentication mechanism.

The client's certificate could be used to sign a token that you could verify. Usually, an authentication token would include some user_id, a timestamp and large nonce. You can pass this via an HTTP header or HTTP query parameter with the request, providing authentication at the app level, not the SSL level.

For Example:

# Half-ass ruby-ish pseudocode
def generate_auth_token(user_id, cert_private_key)
  auth_payload = "#{user_id}::#{timestamp}::#{nonce}"
  token = sign(cert_private_key, auth_payload)
end

def authenticate(cert_public_key, token)
  user_id = extract_user_id(token)
  valid_token = validate_signature(token, cert_public_key)

  valid_token ? user_id : nil 
end

def validate_signature(cert_public_key, token)
  # False if signature isn't valid cryptographically based on key
  # False if timestamp isn't recent
  # False if format isn't legit
  # Otherwise true
end
Phototypy answered 31/1, 2014 at 17:36 Comment(2)
Thanks for the reply. It's basically what Heroku says, too. While your approach works well with service to service communication, it won't work well for browsers. We currently use two-factor auth via ROTP, and are looking into yubikey integration.Intertype
I did some more research and one option with ELB would be to proxy your SSL traffic to a pool of SSL load balancers you control, which could implement SSL termination and client-side cert validation. This eliminates much of the ELB value, imho - but would allow a public load balancer in front of an SSL layer, in front of an application layer.Phototypy

© 2022 - 2024 — McMap. All rights reserved.