I'm currently trying to use IdentityServer4 to build a single-signon experience for my users across different apps I have. They are all hosted in the same local network and no third-party apps authenticate with it. The client apps are still Katana/Owin-based.
I'm using the implicit workflow.
At the moment I still use a certificate randomly generated at runtime to sign tokens.
I wonder
whether I actually need more and what the implications are of leaving it as it is and
how the signature is actually validated by clients.
To the second question I found this piece in the openidconnect spec:
The OP advertises its public keys via its Discovery document, or may
supply this information by other means. The RP declares its public
keys via its Dynamic Registration request, or may communicate this
information by other means.
So does that mean Katana is actually getting the public keys from IdentityServer4 and validates accordingly? And if so, would it matter if it the certificate changes? The time between issuing and validating a token is always very small, correct? So why would I need a proper, rarely-changing certificate?
Generating a new certificate on app startup has a few downsides:
If you restart your IDS4 process you effectively invalidate any otherwise valid tokens as the signature will no longer be valid
Inability to scale out - all servers need to have the same signing and validation keys
Clients might only periodically update their discovery info so you need to allow for a rollover period, something that IDS4 supports as you can have more than one validation key.
See the guidance here: http://docs.identityserver.io/en/release/topics/crypto.html
The next simplest option would be to use a self-issued cert that's installed in the host machine's ceritificate store.
First of all, OpenID Connect discovery is a process of communicating relying party to retrieve provider's information, dynamically. There is a dedicated specification for this, OpenID Connect Discovery 1.0
According to it's metadata section, jwks_uri explains about token signing key publication.
1. So does that mean Katana is actually getting the public keys from IdentityServer4 and validates accordingly?
Yes it should. If your applications (relying parties) want dynamic information, you should go ahead with discovery document to retrieve token signing key information.
2 And if so, would it matter if it the certificate changes? The time between issuing and validating a token is always very small, correct?
Discovery document is part of OpenID Connect dynamic (reference - http://openid.net/connect/ ). So yes, it can be used to convey certificate changes to relying party (token consumers)
3. So why would I need a proper, rarely-changing certificate?
Certificate must be there to validate id tokens issued by identity provider. So at minimum, certificate must live till last token expires. Other than that, one might be using proper certificates issued by a CA, which comes with a cost. So, some implementations could have rarely changing certificates.
Bonus : how the signature is actually validated by clients.
You hash your received message, compare it against decrypted signature using public key of the certificate. Also, if you are wondering the format of key information, it is a JWK defined by RFC7517.
P.S - ID Token validation is same as validating a JWT explained by JWT spec.
Note - I am not an expert in PKI domain. Some expert could point out something else for short lived certificates independent of OpenID Connect protocol.
Related
I want to write a daemon service to visit customer office 365 resource by application identity, from document i found there are two ways to support it one is https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols-oauth-client-creds and the other is https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-certificate-credentials. I want to know what's the different between them and which is the beat solution to implement a daemon service.
thanks
Based on my understanding, the only difference between them is that certificate credential provides a higher level of assurance. For example, you can control the expired time of the client_assertion you generated flexibly. Even it is leaked, the damage will be minimized based on the lifetime of client_assertion.(This is only suppose that HTTPS is not security). If the shared secret was leaked, we will not able to limit it before we detect it and disable the secret.
More detail about client credentials flow, you also can refer link below:
Service to service calls using client credentials (shared secret or certificate)
We currently only use reference tokens as access tokens. This has me wondering if we could just skip the entire certificate management hell by including a self-signed X509 certificate with a ridiculously long validity and store it with our source code (private github) - stop screaming, this might make sense soon.
The worst case I see would be that someone with access to the private key (i.e. any employee or force with access to our github repository) could issue any JWT and use that in the client (angular) - but that's client-side. The APIs are protected via IdentityServer Access Token Validation and all clients are configured to use reference tokens.
Another possible pitfall would be if we ever added a client that uses JWT for access tokens, but I don't really see that happening.
To me, using a long lived self-signed certificate under source-control seems to be the easiest and okay(-ish) solution for this case - unless I've overlooked something. We would never do that with SSL certificates or similar. I'm focussing only on the IdentityServer4 signing credential in combination with exclusive use of reference tokens.
Otherwise we'll have to somehow get certificate rollover (at runtime), certificate management etc. running. I guess we could implement ISigningCredentialStore to manage where the certificates are loaded from - but that still leaves us with the issue on how to handle certificates in a Docker swarm (or just plain Docker containers).
Am I missing something here? Would this solution have any flaws?
Could you not just look it up?
like this
var cert = new CertificateService().GetCertificate(appSettings.CertificateName, StoreName.TrustedPeople, StoreLocation.LocalMachine);
services
.AddSigningCredential(cert);
I am looking into ways of securing the channel between my client apps and the server.
I have a rich desktop client (win) and mobile client connecting to a webservice, exchanging data.
Using SSL certificates, server and clients may trust each other. On the secured connection i can exchange username and password and therefore authenticate the user.
However i have certain circumstances where a user must connect to the server via any of the two methods without his credentials but only a literal, like say, a license plate number.
I really want to make sure that in this case i ONLY allow client connects from devices i am sure i know, since there is no further checks on the authentication and a license plate number would be a pretty common literal.
How can i ensure that only "devices" which are known to my server, can interact with my server?
If you want to authenticate the device, you'll need to find a way for the device to prove what it is, without disclosing its secret.
A system similar to a number plate would be quite easy to spoof, for anyone in a position to see that number. Depending on how much control you have on this device, you might not be able to hide it, even if the connection to your server is secured with SSL/TLS.
A potential way to do this would be to use a cryptographic hardware token (or smart card). Some of these tokens can be configured to hold a certificate and private key, with the ability to use the private key without being able to export that private key. The cryptographic operations (signing and decryption) happen on the token itself.
You can use these to perform client-certificate authentication to your server. In this case, you would know that the client has that token. This could work on the condition that you know the CAs were issued its certificates only for key pairs in such tokens: there will be a cost in administering the CA to handle this.
This would at least allow you to tie the authentication to a particular token. Whether you can integrate this with your overall device depends on the kind of device you have.
Please check if TLS Pre-Shared Keys (RFC 4279) can be used for your scenario.
We're building a REST API that will only be accessed from a known set of servers. My question is, if there is no access directly from any browser based clients, what security mechanisms are required.
Currently Have:
Obviously over HTTPS
Have HTTP auth enabled, API consumers have a Key & password
Is it neccessary to:
Create some changing key, e.g. md5(timestamp + token) that is formed for the request and validated at the endpoint?
Use OAuth (2-legged authentication)?
Doesn't matter - from browser or not.
Is it neccessary to:
Create some changing key, e.g. md5(timestamp + token) that is formed
for the request and validated at the endpoint?
Use oauth (2-legged authorization)?
Use OAuth, it solves both these questions. And OAuth usage is good because:
You aren't reinventing wheel
There are already a lot of libraries and approaches depending on technology stack
You can also use JWT token to pass some security context with custom claims from service to service.
Also as reference you can look how different providers solve the problem. For example Azure Active Directory has on behalf flow for this purpose
https://learn.microsoft.com/en-us/azure/active-directory/develop/v1-oauth2-on-behalf-of-flow
Use of OAuth2/OpenID Connect is not mandatory between your services, there are other protocols and alternatives and even custom. All depends in which relationships are services and either they both are in full trust environment.
You can use anything you like but main idea not to share sensitive information between services like service account credentials or user credentials.
If REST API security is main requirement - OAuth2/OpenID Connect is maybe the best choice, if you need just secure (in a sense of authentication) calls in full trust environment in a simplest way - Kerberos, if you need encrypted custom tunnel between them for data in transit encryption - other options like VPN. It does not make sense to implement somthing custom because if you have Service A and Service B, and would like to make sure call between them is authenticated, then to avoid coupling and sharing senstive information you will always need some central service C as Identity provider. So if you think from tis pov, OAuth2/OIDC is not overkill
Whether the consumers of your API are web browsers or servers you don't control doesn't change the security picture.
If you are using HTTPs and clients already have a key/password then it isn't clear what kind of attack any other mechanism would protect against.
Any compromise on the client side will expose everything anyway.
Firstly - it matters whether a user agent (such as a browser) is involved in call.
If there are only S2S calls then 1 way SSL HTTPS (for network encryption) and some kind of signature mechanism (SHA-256) should be enough for your security.
However if you return sensitive information in your api response, its always better to accept 2 way ssl HTTPS connections (in order to validate the client).
OAuth2 doesn't add any value in a server to server call (that takes place without user consent and without any user agent present).
For authentication between servers:
Authentication
Known servers:
use TLS with X.509 client certificates (TLS with mutual authentication).
issue the client certificates with a common CA (certificate authority). That way, the servers need only have the CA certificate or public key in the truststore, and new client certificates for additional clients/servers can be issued without having to update the truststores.
Open set of servers:
use API keys, issued by a central authority. The servers need to validate these keys on each request (and may cache the hashes of the keys along with the validation result for some short time).
Identity propagation
if the requests are executed in the context of a non-technical user, use JWT (or SAML) for identity propagation of the user principal and claims (authorize at security proxy/WAF/IAM, and issue JWT signed by authentication server).
otherwise the user principal refers to the technical user and can can be extracted from the client certificate (X.509 DName) or be returned with a successful authentication response (API key case).
I'm trying to figure out the best way to secure an API. I only allow SSL and I'm using OAuth2 for authentication, but that doesn't seem like enough.
The major concern I have is that anyone could inspect the requests being made by a legitimate client to the API and steal the OAuth client_id. At that point they would be able to construct any request they want to impersonate the legitimate client.
Is there any way to prevent this? I've seen people use a HMAC hash of the parameters using a secret key known only to the client and server but I see 2 problems with that.
It's very difficult (impossible?) to prevent a malicious user from decompiling your client and figuring out the secret key.
Some parameters seem odd to make an HMAC hash of. For example if a parameter was bytes of a file, do you include the whole thing in your HMAC hash?
You can deploy mutually-authenticated SSL between your legitimate clients and your API. Generate a self-signed SSL client certificate and store that within your client. Configure your server to require client-side authentication and only accept the certificate(s) you've deployed to your clients. If someone/something attempting to connect does not have that client certificate, it will be unable to establish an SSL session and the connection will not be made. Assuming you control the legitimate clients and the servers, you don't need a CA-issued certificate here; just use self-signed certificates since you control both the client-side and server-side certificate trust.
Now, you do call out that it's really hard to prevent someone from reverse engineering your client and recovering your credential (the private key belonging to the client certificate, in this case). And you're right. You'll normally store that key (and the certificate) in a keystore of sometype (a KeyStore if you're using Android) and that keystore will be encrypted. That encryption is based on a password, so you'll either need to (1) store that password in your client somewhere, or (2) ask the user for the password when they start your client app. What you need to do depends on your usecase. If (2) is acceptable, then you've protected your credential against reverse engineering since it will be encrypted and the password will not be stored anywhere (but the user will need to type it in everytime). If you do (1), then someone will be able to reverse engineer your client, get the password, get the keystore, decrypt the private key and certificate, and create another client that will be able to connect to the server.
There is nothing you can do to prevent this; you can make reverse engineering your code harder (by obfuscation, etc) but you cannot make it impossible. You need to determine what the risk you are trying to mitigate with these approaches is and how much work is worth doing to mitigate it.
Are you running the OAuth authentication step over SSL itself? That prevents all kinds of snooping though it does mean you'll have to be careful to keep your OAuth server's certificate up to date. (Note, the OAuth server can have a public SSL identity; it's still impossible to forge with even vaguely-reasonable amounts of effort. It's only the private key that needs to be kept secret.)
That said, you need to be more careful about what you are protecting against. Why do people have to use your client code at all? Why does it have to be “secret”? Easier to give that away and put the smarts (including verification of login identity) on your server. If someone wants to write their own client, let them. If someone wants to wave their account in public in a silly way, charge them the costs they incur from their foolishness…