I am creating JWT based authentication in my application deployed on Wildfly server.
For any request arriving at my server, the request is validated to be having a Basic Auth header. In cases, where I don't get the header, I get the POST request payload with Username and Password. I wrap the request with HttpServletRequestWrapper and add Basic auth header to it and call another application which returns 200 OK after authenticating with Login module automatically. Also, I have a singleton with a ConcurrentHashMap<String, MyUser> in which I store user logging in and the User object with other user details.
On receiving 200 OK, I create a JWT and return it to the client. The client then sends JWT with each request to the EJB services. I get the Authorization header as Bearer *******. I decode the user from the JWT token, then using the map, I again create Basic Auth header and send request to another application which exposes the services only when the Basic Auth header is found.
My doubts:
a) In 1) above, I am sending POST payload, which I can see in Browser network logs. And, I can plainly see the username and password being sent. Is there something extra that needs to be done to prevent this. Or, this wont be visible to other users? Or, https is the solution?
b) In 2) above, anybody can get my token if they are doing MITM attack or know my credentials as in a).
Then, they can seamlessly get access the services. Can, I add IP address of the requested user and store in the map and while validating JWT, validate the IP as well so I can prevent MITM attacks?
There are other posts on SFO and Okta Developer I visited, and they answered about why and how JWT is insecure. But, I am curious, if I can do anything extra in my case which I am missing?
There are several levers you can pull here to vary the amount of security in your JWT setup. Consider the following options:
No SSL and no encryption of your JWT. In this case, your JWT would be visible not only to the user, but also to any man in the middle who is listening (either legitimately or maliciously). This means that any sensitive information contained within the JWT might be visible to others. However, the JWT still cannot be hacked, even in this maximally unsecure setup. The reason for this is that every JWT contains a checksum, which is a hash of the token's content, signed using a key which only the server has. So even if a MITM or user messes around with your JWT, the server would immediately recognize that the token has been hacked when the checksum fails.
SSL is enabled, but the JWT is not encrypted. This offers the same protection as above plus it also makes it very unlikely that a MITM could ever get a hold of any JWT going to or fro in transit. Therefore, sensitive information inside the JWT would only be visible to the recipient.
SSL is enabled, and the token is encrypted. In this maximally secure setup, no MITM can see the JWT in transit. Also, once received, the user must decrypt the JWT using some key. Therefore, even if the JWT ends up in a cookie, in theory it is not a security risk, provided that it can't be decrypted by anyone other than the intended recipient.
Most of the time, we will tend to lean towards option #2, but we will not put sensitive information into the JWT. There is no need for storing a login password in a JWT, as the token itself can prove authentication. The JWT is tamper proof, and if someone malicious finds a way to see claims such as the expiry date or username, we generally don't care.
1 -> Yes HTTPS is the only solution no matter how much secure you make your APIs without
HTTPS MITM attacks are easy.
2-> With multiple benefits come some tradeoffs, JWT leak or stealing is a real problem, and it is not easy to solve, adding an IP address to JWT is not a good idea as they get to change a lot and you user have to authenticate again.
What you try is a quick JWT expiration in this case user has to authenticate every time the token is expired, now for solving this problem you can use a refresh token, it is not so hard to implement.
wanna get deeper here you go --> https://www.youtube.com/watch?v=DPrhem174Ws&t=1089s
Related
I'm writing a mobile app that communicates to a remote Java service via REST. I have protected my (SpringBoot) web service with https protection (due to the nature of the data, it needs to be secure) but my question is about which user/password I use to secure the https calls.
Should the username and password I use in the https header be a service account that the client (mobile app) and Java service knows or should it be the public user's username and password? The easiest option is just to use a service account but this means the mobile app will have those details built into it and distributed publically (albeit in compiled form).
Going the other way and using the user's username and password means I'll have to have the logon REST endpoint open and unsecure (which is fine I guess), but it just makes it slightly more fiddly.
Good question, and I would reckon you to use token based authentication and authorization scheme. Firstly you should have a login page where client logs in by providing username and password which is authenticated by calling some remote login service which maintains it's own user store or may use an existing one in your organization if any. Upon a successful authentication, the auth service should provide the client with a valid token, which then be refreshed time to time. The mobile or web client should pass in the token to the downstream microservices when a request is sent and this token should be sent inside the Authorization HTTP header.
Exposing the username and password while passing it around the network normally not considered as a good solution and that's where token becomes handy too. Token is the normal procedure that people use to secure rest endpoints. Yous rest endpoint should intercept each and every request comes at it, passes the token to the auth provider and verifies that. If the token is valid it will allow the request otherwise it should deny it.
Security is a pretty much larger topic and you have X.509 certificates other than tokens to encrypt the data sent across the wire over https and so forth. I suggest you to take a look at the spring security documentation since that will be a good starting point. Spring Security gives lots of hooks for developers which can be used out of the box with some sensible defaults. You can use JWT style tokens, Oauth tokens and spring security supports all these different forms too.
I logged in as Scott who only has read permission. The oauth2 server(JAVA based) gave me a token. Then I asked my teammate to send me his non-expired token. I updated my Angular application and hardcoded the token that was given to me. I tried to make changes to the api and I was able to make some change.
How can backend api prevent this?
You've successfully implemented a session hijack. This happens because sessions are based on tokens stored in the web page or cookies rather than IP addresses or something. This makes sense because IP addresses can be spoofed while a cryptographically secure session token is practically impossible to spoof.
While you could add strategies to make this more difficult (eg: some kind of hardware token that is involved in cryptographically signing every message), why do you feel you need to? All but the most secure sites rely on this mechanism.
I would like to know what is the best practice on how to work with authorized RESTful server.
Say that after login the server provides me a token, and then for each request I will have to provide it as well. My question is: should I save this token in my server's session? or should I do authentication against the data base for each request?
There are several ways. You could only keep it in memory, but then if you have multiple servers in a cluster, you'll have to make sure a request for a given token always goes to the same server, or to distribute the token among all the servers.
You could also cryptographically sign the token data, include the data and the signature in the token, and verify the signature at each request. That way you can be certain that the token has been issued by you, and you can be completely stateless.
Note that, if you're using HTTP sessions already, the token is redundant, since the session mechanism already uses a token in a cookie to track sessions.
Use a session cookie to track an authenticated session instead of hitting the database each time.
The answer below is from this question;
The awarded answer doesn't actually address the question at all. It only mentions SSL in the context of data transfer and doesn't actually cover authentication.
You're really asking about securely authenticating REST API clients. Unless you're using TLS client authentication, SSL alone is NOT a viable authentication mechanism for a REST API. SSL without client authc only authenticates the server, which is irrelevant for most REST APIs.
If you don't use TLS client authentication you'll need to use something like a digest-based authentication scheme (like Amazon Web Service's custom scheme) or OAuth or even HTTP Basic authentication (but over SSL only).
So considering I will use HTTPS without client certification
my question here is poster says if we dont use client SSL certification server does not really know whom its talking to. What I understand here is if I use a authentication-token to access to authenticate the client against the server. Then server does not know whom is sending the token even if that token is paired with a user id in my servers database.
First of all
1-is this a real problem? If I especialy use Https?(without TLS client authentication)
2- and most important, assuming that is an important security flaw; How can Http basic authentication help here as poster mentioned? Http basic authentication just sends encoded username password in a header. So when client receives a token (in return after he sends his username password) then for the rest of his requests he will use this token in this header instead of password, and everything is fine all of a sudden?
Still Server does not know from where the request is coming from, maybe server has a valid token with a matched user in its database but unknown who reallysend it.
(while I still see this very hard that the token would be stolen over https and used by someone else!)
Whenever I bring this subject I get replies.."Well..you send a token but server does not know whom send the token, not very secure" so I understand this as the browser keeps a sort of auth-certification and server knows where the request is coming from the right place THEN I can be sure that the paired user with that token (checked from my DB)is "really correct"
Or maybe what am telling here is not correct
[the] poster says if we dont use client SSL certification server does not really know whom its talking to.
That's not what I said :) This is what I said:
Unless you're using TLS client authentication, SSL alone is NOT a viable authentication mechanism for a REST API.
alone being the key word here. Also:
If you don't use TLS client authentication, you'll need to use something like a digest-based authentication scheme (like Amazon Web Service's custom scheme) or OAuth or even HTTP Basic authentication (but over SSL only).
In other words, TLS client authentication is one way of authenticating a REST API client. Because the original SO question was about SSL specifically, I was mentioning that TLS client authc is the only 'built in' form of authentication if you're relying on TLS alone. Therefore, if you're using TLS, and you don't leverage TLS client authc, you must use another form of authentication to authenticate your client.
There are many ways to authenticate REST Clients. TLS client authc is just one of them (the only 'built in' one for TLS and usually very secure). However, TLS is a network-level protocol and is perceived by most to be too complicated for many end-users to configure. So most REST API offerings opt for an easier-to-use application-level protocol like HTTP because it is easier for most to use (e.g. just set an HTTP header).
So, if you're going the HTTP header route, you have to use a header value to authenticate a REST client.
In HTTP authentication, you have a header, Authorization, and its value (the header name is rather unfortunate because it is usually used for authentication and not as often for access control, aka authorization). The Authorization header value is what is used by the server to perform authentication, and it is composed (usually) of three tokens
An HTTP authentication scheme name, followed by
white space (almost always a space character), followed by
The scheme-specific text value.
One common HTTP authentication Scheme is the Basic scheme, which is very... well... basic :). The scheme-specific text value is simply the following computed value:
String concatenated = username + ":" + raw_password;
String schemeSpecificTextValue = base_64_encode(concatenated.toCharArray());
So you might see a corresponding header look like this:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
The server knows how to parse the value. It says "Hey, I know the Basic scheme, so I'm going to take the trailing text value, base64 decode it, and then I'll have the username and submitted password. Then I can see if those values match what I have stored."
And that's essentially Basic authentication. Because this scheme in particular includes the submitted raw password base64 encoded, it is not considered secure unless you use a TLS connection. TLS guarantees (mostly) that prying eyes can't intercept the headers (e.g. via packet inspection) and see what the password is. This is why you should always use TLS with HTTP Basic authentication. Even in company intranet environments.
There are other even more secure HTTP Authentication schemes of course. An example is any scheme that that uses digest-based authentication.
Digest-based authentication schemes are better because their scheme text value does not contain the submitted password. Instead, a password-based-hash of certain data (often other header fields and values) is calculated and the result is put in the Authorization header value. The server calculates the same password-based-hash using the password it has stored locally. If the server's computed value matches the request's header value, the server can consider the request authenticated.
Here's why this technique is more secure: only a hash is transmitted - not the raw password itself. That means this technique can be used to authenticate requests even over clear-text (non TLS) connections (but you would only want to do this if the request data itself is not sensitive of course).
Some digest-based authentication schemes:
OAuth 1.0a, aka RFC 5849.
HTTP Digest Access authentication (used by browsers natively).
Amazon AWS's custom scheme.
Amazon's and others like it are more secure for REST than OAuth 1.0a because they always authenticate the entire request - including the request entity payload (i.e. all the stuff after the HTTP headers too). OAuth 1.0a only does this for application/x-www-form-urlencoded content which isn't relevant for REST APIs that use application/xml or application/json payloads (which are most REST APIs these days).
Interestingly, OAuth2 is not digest based - it uses something I consider less secure, called 'bearer tokens' (which are honestly fine in many scenarios but still not as good as the digest schemes used in banking, military, and government communication).
When we talk about "authenticating a user", what we really mean is "checking that the user knows something nobody else should know". That "something" might be a password, a certificate, a hardware security token or even the user's retinal pattern, but in all cases it's the access to that information that we're really checking, not the identity of the user (whatever that really means) as such.
The point is that, in principle, all these authenticators could be stolen and used to impersonate the user. A password could be logged, a certificate could be copied from the disk it's stored on, a hardware token could be stolen (and possibly reverse engineered and cloned) and even the user's retinal pattern could, in principle, be scanned, recorded and faked. the best we can do is, in each case, to try to make this as "very hard" as possible.
Maybe I'm misunderstanding the question.
The answer you have quoted says to me that if you don't use some form of authentication, whether it is client certificates, HTTP BASICAUTH, or something else, the server doesn't know with whom it is communicating.
(Maybe that's okay for your application, maybe it isn't, only you can answer that.)
Stated in other terms, if you do use some form of authentication, the server does know with whom it is communicating; it is communicating with the "person" to whom the authenticated credentials belong.
In this context, authentication is the process of establishing identity via some credentials.
Authentication does not guarantee that the credentials have not been stolen. SSL assures (I wouldn't go so far as to say it "guarantees") the credentials are secure in transit between client and server.
When you use GMail, you're using SSL, how does Google know it's talking to you?
My company is building a RESTful API that will return moderately sensitive information (i.e. financial information, but not account numbers). I have control over the RESTful API code/server and also am building the Android app. I've setup the API to use OAuth 2 with authorization code grant flow (with client ID and secret), and I auto-approve users without them having to approve the client since we own both client and provider. We use CAS for SSO and I am using this for the Authorization server as part of the OAuth 2 process when the user logs in to retrieve the token.
I am contemplating various ways to secure the data on the Android app. I've concluded that storing the client id and secret on the device is definitely not going to happen, but am thinking that storing the auth token might work, since it is only risk to the individual user (and really only if they happen to have a rooted phone).
Here are two options I have thought of. They both require me to have a sort of proxy server that is CAS protected, does the dance with the API server, and returns the auth token. This gets rid of the need for storing the client id and secret in the app code.
Here are what I've come up with:
1) Require the user to enter their password to access data each time they startup the App. This is definitely the most foolproof method. If this were done, I'd probably want to save the userID for convenience, but in that case couldn't use the CAS login (since it's web-based). I might be able to use a headless browser on the backend to log the user into CAS and retrieve the token based on what they enter in the Android form, but this seems hacky. Saving the userID is similar to what the Chase app does (if you happen to use this one) - it saves the userID but not your password between sessions.
2) Store the auth token on the Android device. This is a little less secure, but almost foolproof. When the user starts the app for the first time, open the webpage to the CAS login of the proxy server that returns the token (similar to https://developers.google.com/accounts/docs/MobileApps). After the user logs in and the token is returned to the app, encrypt it and store it private to the application. Also, use ProGuard to obfuscate the code, making the encryption algorithm more difficult to reverse engineer. I could also work in a token refresh, but I think this would be more of a false sense of security.
3) Don't use CAS but come up with another way to get an auth token for the service.
Any advice of how others have implemented similar scenarios (if it's been done)?
Thanks.
Well the reason why standards like OAuth are developed is that not everyone has to rethink the same attack vectors again and again. So most often it is your best choice to stick to something already available instead of baking your own thing.
The first problem with clients that are not capable of secretly storing data is that the user's data could be accessed by some attacker. As it is technically not possible to prevent this (code obfuscation won't help you against an expert attacker), the access token in OAuth 2 typically expires after short time and doesn't give an attacker full access (bounded by scope). Certainly you shouldn't store any refresh token on such a device.
The second problem is client impersonation. An attacker could steal your client secret and access your API in his own (maybe malicious) app. The user would still have to login there himself. The OAuth draft there requires the server to do everything it can to prevent this, but it is really hard.
The authorization server MUST authenticate the client whenever possible. If the authorization server cannot authenticate the client due to the client's nature, the authorization server MUST require the registration of any redirection URI used for receiving authorization responses, and SHOULD utilize other means to protect resource owners from such potentially malicious clients. For example, the authorization server can engage the resource owner to assist in identifying the client and its origin.
I think Google are the first to try another approach to authenticate a client on such devices, by checking the signature of the application, but they are not yet ready for prime time. If you want more insight into that approach, see my answer here.
For now, your best bet is to stay on the OAuth way, i.e. having the access token, client ID and client secrect (when using the authorization code grant flow) on the device, and configure your server to do additional checks. If you feel more secure obfuscating these, just do it, but always think of it as if these values were publicly available.