I want to setup secure interaction between my server and clients and I would like to avoid inventing square wheel.
There is a "REST-Server" in SpringBoot
Service has many "REST-clients" in Java installed somewhere. I don't control it.
"REST-Server" generates public/private key pair for every(!) client and shares pub key with client
every "REST-client" generates it's own public/private key pair and shares public key with "REST-Server". Client shares it's public key along with unique id.
"REST-clients" poll ""REST-server" from time to time
"REST-client" sends request in from:
clientId (helps "REST-Server" to locate right client pub key to decrypt message)
payload encoded with "REST-Server" public key assigned for a given client
original message SHA so "REST-Server" can verify if payload was decrypted correctly
client signature created with client's private key, so server can verify if message comes from authorised client
"REST-server"
locates private key associated with a client by "uniqieId"
decrypts and verifies it with SHA
verifies sender with client signature and known client's pubic key
"REST-server" sends response in form
payload encoded with "Client"'s public key
original message SHA so "client" can verify if payload was decrypted correctly
"REST-client" decrypts response using own private key.
Is there any library / spingboot extension that can do most parts of it?
I would focus more on the client angle than the server one:
Some clients can keep a secret (back end / confidential clients)
Some clients cannot (web / mobile UIs - public clients)
If a client API credential is compromised then you may have a permanent security breach
This feels like a problem that OAuth 2.x solves:
Supports both type of client
Apps work with tokens and never use API credentials directly
Even if a token is stolen it expires shortly after
Threat models are reviewed by experts
In Java I would use a respected OAuth library such as NimbusDS.
Related
As JWT tokens are sent over the headers to authenticate uses, a user can just inspect the web call in chrome dev tools and copy paste the token and use it to access the exposed API.
For example, if I am using this token to create a record, a malicious user can use the same token (by using the above mentioned way) to create a new record in Database.
How can I stop this from happening? Is using Token Encryption with public key of server the way to stop this?
Token represents user identity. It is normal, that user can view his own token.
Token is validated on the server. Normally there is is no easy way to fake a token. Use cannot generate a new token on his own.
Communication between browser and server should be done via TLS. Then no third party will be able to see the token.
If your user gives access to his browser to somebody else, then yes, the other person can potentially access the token and used it later on on another computer, it this token is not expired yet. But this is not specific to the token, this is like giving access to your password to smb else.
Several steps can be taken as given below:
You should use https connection instead of http connection. This will encrypt your message which is sent to server or received from server. So if a man in the middle catches your packet, he can't do anything because message is encrypted.
Also add a short time validity for jwt token depending your app behavior.
Add an appropriate key size for your self-signed token validation. AES keys shorter than 128 bits, or RSA keys shorter than 1024 bits for legacy apps.2048 bits encryption now a days popular.
HSM (Hardware Security Module) can be introduce for signing and encryption task while key are not accessible from OS or software level.
You should be digging deep for more here[cheat sheet for jwt token OWASP].
According to this and this there are two ways to validate the JWT token:
Using RemoteTokenServices which basically calls /check_token endpoint of oauth server, retrieves the whole token and compares it
Expose public key at oauth server and verify the JWT's signature at resource server
At the beginning I tried the first way but since I use custom token converter which hits the database every time token being generated, I decided to switch to signature verification at resource side - didn't want to get an additional database call per every client request.
After some investigation I realized that ResourceServerTokenServices (interface describes token retrieval, conversion and generation a valid OAuth2Authentication object) has only two default implementations: DefaultTokenServices which is primary used in case of oauth and resource servers are parts of the same application and RemoteTokenServices which was described in first approach.
So the main question is whether spring-oauth2 really hasn't default implementation of JWT signature verification or I just couldn't find one?
You do not need a JWT specific ResourceServerTokenServices, so the DefaultTokenServices should do fine. Most of the implementation specific details are sent to the store, so as long as you have a JwtTokenStore configured correctly there should be no issue.
Here :
The Resource Server also needs to be able to decode the tokens so the JwtTokenStore has a dependency on a JwtAccessTokenConverter, and the same implementation is needed by both the Authorization Server and the Resource Server. The tokens are signed by default, and the Resource Server also has to be able to verify the signature, so it either needs the same symmetric (signing) key as the Authorization Server (shared secret, or symmetric key), or it needs the public key (verifier key) that matches the private key (signing key) in the Authorization Server (public-private or asymmetric key). The public key (if available) is exposed by the Authorization Server on the /oauth/token_key endpoint
You can extend JwtAccessTokenConverter to access once the Authorization Server for the exposed public key.
I am implementing an app that connects to an OAuth2 server and it gets back a Json Web Token (JWT). I am passing the token along and I want to independently validate that the token came from the issuing source.
I can do this, no problem, with the public key from the issuing source. I have it available to me for now. Everything works.
But what if the OAuth server changes the signing key? How does the validating app get the new key? Is there a "best practices" convention for sharing the public key from an OAuth2 server? Do we just expose it from an endpoint on the auth server?
There's no solution that is standardized as part of the OAuth 2.0 protocol suite (today).
It was considered to be a single-domain problem that would be solved in various ways that were considered to be out of scope for the core OAuth specifications (much like the API between Resource Server and Authorization Server is/was), and much like any PKI based mechanism in general works today.
But OpenID Connect is a cross-domain SSO protocol that was built on top of OAuth 2.0, which also defined a more standardized option of dealing with key distribution in the form of JWKs URIs as part of the Discover, see the jwks_uri entry at:
REQUIRED. URL of the OP's JSON Web Key Set [JWK] document. This
contains the signing key(s) the RP uses to validate signatures from
the OP. The JWK Set MAY also contain the Server's encryption key(s),
which are used by RPs to encrypt requests to the Server. When both
signing and encryption keys are made available, a use (Key Use)
parameter value is REQUIRED for all keys in the referenced JWK Set to
indicate each key's intended usage. Although some algorithms allow the
same key to be used for both signatures and encryption, doing so is
NOT RECOMMENDED, as it is less secure. The JWK x5c parameter MAY be
used to provide X.509 representations of keys provided. When used, the
bare key values MUST still be present and MUST match those in the
certificate.
This would expose the key material over HTTPs protected channel, effectively leveraging the SSL CA for publishing and rollover of JWT signing key material.
At some point the jwks_uri definition may be part of the standardized OAuth 2.0 protocol extensions as well, but for now you'd have to rely on a custom agreement between Client and Authorization Server to do so. That may not be too hard to implement yourself though.
You may get lucky if your Authorization Server happens to be an OpenID Connect provider as well and uses the same key material for signing ID tokens as well as JWT access tokens.
Updated 4/22/2019: the Authorization Server metadata document is now also standardized it its own OAuth 2.0 extension OAuth 2.0 Authorization Server Metadata RFC8414
I want to use OAuth JWT token for authorization. By some reasons (osgi container) I can't use spring-oauth-security.
In the readme of spring-oauth-security I have found a quote:
The JSON Web Token (JWT) version of the store encodes all the data about the grant into the token itself (so no back end store at all which is a significant advantage).
https://github.com/spring-projects/spring-security-oauth/blob/master/docs/oauth2.md
I am absolutely don't catch "no back end store at all". There are two cases in jwt:
symmetric key or shared secret (HMAC);
Verifier key is a shared secret and is available by /token_key URL.
Question 1: I should store shared secret on server for each registered user. Why "no back end store at all"?
asymmetric key (RS/ES);
/token_key returns public key (without principal).
Question 2: But why we use only one public key for all users? It is unable to generate more than one private key for the same public key in rsa, isn't it? Only one pair private key - public key is allowed in RSA.
I don't understand a flow and why "no back end store at all".
You do not use different keys per user but per Identity Provider.
Identity Provider signs a JWT with a key and you are able to validate it for each user without a backend lookup. For JWT validation you only need a key related to the Identity Provider - even if you store it on some DB, you could fetch it once and cache it. For assymetric keys, OIDC even defines a URL to fetch the public key(s) used for signature.
The key is used to trust the Identity Provider and thus implicitly the identities it provides.
This is quite good article on the topic:
https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/
Looks like the solutions out there for securing ASP.NET Web API is pretty scattered, so I decided to roll my own public/private key encryption scheme. Please take a look at my workflow and help me answer a question I'm stuck on at the end. (Again, it's specific to .NET 4.0 Web API framework)
User register at my Web MVC 4.0 website.
Once registered, my website does 4 things
a) Generate a RSA server public key for this user
b). Generate a RSA server private key for this user
c). Generate a RSA client public key for this user
d). Generate a RSA client private key for this user
I save all 4 keys to this user account in database and give the user the server public key, called the "APIKey" as well as the client private key, called "SecretKey". This is for future handshake purpose. User will never know about the server private key nor the client public key.
Once user confirms they have the keys, I delete the "client private key" from my database for security purpose.
User starts to request my WebAPI authentication service by submitting the server public key (or APIKey)+":"+encrypted message of (username,password) using the RSA server public key (APIKey)
Server receives the APIKey+":"+encrypted message, find the private key, decrypt the message, get username,password, and use Membership provider to make sure they are correct.
If not correct, then create a denied response. Otherwise, it finds the Client Public Key on record for the user, create a unique time sensitive session token (expires in 5 minutes), record it in database + time created, and use the client public key to encrypt the token and send it back to the client.
Client receives the response, use it's "Client private key" or "Secret Key" to decrypt the response, get the token.
User makes other requests to the service by using Server Public Key to encrypt the following
a) session token
b) timestamp (so I can make sure replay attack doesn't happen)
c) data
and send to the server its APIKEy+":"+encrypted message
What i'm stuck on is step 9 and beyond.
Is that necessary at step 9 to still use public / private key to communicate? The reason I'm asking is because browsers communicate with servers through SSL, at the end, once handshake happens, they use an agreed cipher suite symmetric algorithm to pass message back and forth, supposedly it's faster? But if we do that, will it be secure from this point on wards?
In that case, where in my workflow can I exchange this agreement between my Web API and Client to use the same symmetric algorithm to encrypt/decrypt information back and forth?
Thanks!!
Edit: If you see a flaw in this workflow, please do let me know! Greatly appreciate it.
You are probably looking to make a secure authentication without need for domains/user auth so you want server client cert exchange right? ATK is right if you just want encrypted traffic (which you should use anyway for the exchange), but for actually using it as auth, this article is really useful: http://codebetter.com/johnvpetersen/2012/04/02/making-your-asp-net-web-apis-secure/
Please don't roll your own scheme. Crypto is very hard to get right, even by the experts. A very subtle error can completely remove all security provided by the scheme. Just look at the attacks on SSL/TLS over the past few years for examples.
You mention a "web api" but it's unclear exactly what protocol you are using. If you are using SOAP, use "Web Security" (WS), which is well defined for SOAP. If you are communicating over HTTP (ex REST), use HTTPS. If you are communicating over a connected channel, use TLS or SSH.
EDIT: Per http://msdn.microsoft.com/en-us/library/hh833994(v=vs.108).aspx,
ASP.NET Web API is a framework that makes it easy to build HTTP
services that reach a broad range of clients, including browsers and
mobile devices. ASP.NET Web API is an ideal platform for building
RESTful applications on the .NET Framework
This means you probably want to use HTTPS.