I use Java NIO secured by SSL to connect client and server. To connect to a server the user is prompted to enter host, port, username and password. So far I can connect client and server (they successfully complete their SSL handshake) and I could theoretically start sending data back and forth. I have not written a mechanism to verify login credentials (username, password) yet.
The server can authenticate username and password by looking them up in a database. If the credentials a client sends are incorrect, the connection will be closed.
Question 1: When should the credentials be validated? I assume this has to happen after the SSL handshake.
Question 2: How do I securely package the credentials before they are serialized and sent to the server? I assume I should hash the password. Should I hash the username too?
Would something simple like this suffice?
public class LoginCredentials implements Serializable {
private static final long serialVersionUID = 1026410425432118798L;
private final String username;
private final byte[] passwordHash;
public LoginCredentials(String username, byte[] passwordHash) {
this.username = username;
this.passwordHash = passwordHash;
}
public final String getUsername() {
return username;
}
public final byte[] getPasswordHash() {
return passwordHash;
}
}
Question 3: Authenticating credentials should be done once per session, correct? I read some posts that seemed to indicate the credentials should be verified for every request.
Question 4: Which hashing algorithm should I use? SHA–512 seems to be very popular.
of course that after ssl handshake, when the ssl connection is established, this makes it more secure
Not many applications really do that, most of them just sends the password over ssl not hashing it at all. Yes, you can generate a hash, but the hash should be generated for every login, so it will not be always the same, this requires some code on client side to resolve some challenge which includes the correct password and some random thing sent by server, otherwise it would not differ much from regular password authentication. But there is plenty of authentication mechanisms - passwords, hashes, tokens, ssl certificates to name a few.
you need to check if the authenticated user has access rights to the resource He tries to access - this is for every request, not to login the user for every request if you have session. If you need to manage the user access rights to grant or revoke access during single session then you need to read the user access rights for every request, if you don't need such granularity then reading them once for the whole session is ok. Sometimes there are sessionless services eg. some REST, then typically you need to send some credentials on every call.
You can use any hashing algorithm that's not too easy to decipher.
Related
I am writing a REST client in Java using the HttpCLient , the REST API that I access needs an auth token for every REST action. This token is valid for 24 hours.
The way I am handling this now is calling a "getAuth()" method everytime I need to make a REST call which seems like an overhead on the auth server.
How can I conveniently store this auth token and manage its life cycle?
Are there any documented best practices?
I thought of the following solution
public class MySession {
String user;
String pass;
public MySession(String user, String pass) {
this.user = user;
this.pass = pass;
}
public getAuth() {
//user user, pass to get auth token
}
}
and then pass the sessions object to any class that nees the token. If the token is expired, just call this method again
For brevity I'll assuming you're calling an endpoint that you can't change. How you should implement will heavily depend on whether the token is app or user based (one token for all users on a shared app instance or one token per user).
If it's one auth token for the entire app:
Store it in memory along with a time-to-live timestamp (or alternatively catch the token expired error, request a new token and retry the original request), refresh it if it doesn't exist/is expired
If you're concerned about re-requesting API tokens after an application restart also store it in the database and load it at startup if it exists
If it's one token per user:
Store it in your user session, it's exactly what sessions are used for, if you're authing users then they'll have a session and the overhead is already there
If you don't want to re-request a token everytime they login store their current token in the DB and and load it into their session when they login
I'm assuming you are using OAuth for authorization. Whether you are using JWT or other tokens is irrelevant to this situation.
When performing authorization you will be issued an access_token with an expiration and, depending on the grant type you are requesting (Client credentials, Authorization code, Implicit, Resource owner), a refresh_token.
The client should keep the access_token and the expiration. The refresh_token, if issued, must be kept secret (beware of using the correct grant for your use case).
In subsequent calls, your client should not request new tokens on each call, it should use the stored access_token.
Once the API starts returning 401 Unauthorized, the access_token has probably expired. Your client should try to refresh the access_token using the refresh_token if you got one.
If you have no refresh_token or the refresh request also failed, because the refresh_token is no longer valid, you can perform a new authorization flow.
You can use the expiration time as a clue to know when to get a new access_token either through refresh or through a new full authorization flow. This will avoid the 401 Unauthorized. In any case, your client should have a fall back policy when this response is received after having used a valid access_token for some calls.
You can create a manager and store the auth-cookie during login in thread local like the code below. You can get the cookie from getAuth() as long as the thread lives.
public class Manager {
private static final ThreadLocal<String> SECURITY_CONTEXT = new ThreadLocal<>();
public static void setAuth(String auth) {
SECURITY_CONTEXT.set(auth);
}
public static String getAuth() {
return SECURITY_CONTEXT.get();
}
public static void clear(){
SECURITY_CONTEXT.remove();
}
}
I suggest you to use the following scenario:
1) First, call auth(username, password) rest api to get the auth token.
If the given credentials are okay then just send back the auth cookie to the client with HTTP 200 response code.
2) Then, you can call protected rest apis. You need to send auth cookie with your request each time.
3) Servlet filter (or something similar) checks each incoming request and validates the token. If the token is valid then the request goes forward to the rest method, if not you need to generate an http 401/403 response.
I suggest you not to write your own authentication layer. Instead of install and use an existing one. I suggest you OpenAM. It is a superb open source access management system.
I also suggest you not to open session on the server side for authentication purpose. If you have 10 clients then 10 sessions needs to be managed by server. It is not a big issue. But if you have 100 or 1000 or millions different clients than you need more memory to store sessions on the server.
If you are worried about too many hits to the database, then i'm assuming there is a lot of web activity.
I would not recommend using Session in your case, but rather store the token in a cookie on the client.
In a high traffic environment(which i'm assuming yours is), the use of Session can consume a lot of server memory, and scalability can be a concern as well, having to keep sessions in sync within a cluster.
As #Cássio Mazzochi Molin also mentioned, you can use an in-memory cache to store any user specific data and tokens. This will reduce the hits to the database, and also allow you to scale the application easier, when the need arises.
The de-facto standard is not implementing your own solution (basic rule in security: don't implement your own stuff!), but use the de-facto standard solution, namely JSON Web Tokens.
Documentation on the site, but the basic idea is, that you only need to store one value (the server's private key), and then you can verify every claim, issued originally by the server (which will in your case contain an expiry time).
You should use JsonWebToken (JWT in short) for this kind of stuff. JWT has build in support to set the expiration date. There are plenty of libraries to use this method and you can read more here
There are currenlty 4 java implementations and all of them can check if the token is still valid (exp check)
So if I'm understanding correctly you are using the same token for all of your requests (which means as long as your app is up and running and you refreshing the tokens, you should be ok. I literally had the same problem and this is how I've resolved it. I have a singleton class, which is initialized at the app start for once and refreshes the token when its invalidated. I'm using C#, Asp.NET MVC5 and AutoFac for DI, but I'm sure you can do the same with Java and Spring.
Updating property of a singleton with Thread Safety
Use json web tokens , to exchange information between two clients. The token will only alive for the 24 hours period, after that time all consequent calls in the header will be rejected.
Auth Token for each request is correct approach, Consider auth server scaling for performance issue.
On first successful authentication (username and password), generate private public keypair. Store private key as Session Security Token (SST) and send public key as Public Security Client Key (PSCK) to client
In all request other than login (or authentication) client will send PSCK to protect theft of username and password and server can verify PSCK for expiry internally at regular intervals saving processing time.
If system is having performance issue on authentication side, setup seperate auth server with scalability.
No token or password to be cached, exchanged unencrypted and send outside security zone. Do not post using URL parameters.
In general what is the best way to authenticate the access token in interceptors, If the access token information is stored in HashMap for each and every user, the hashmap grows as the number of users increases.
If we query database for every api request, it increases load on database.
Please mention if there are any other techniques you know.
And also what other things I need to consider while authenticating the access token for every request. What are the pre-processing and post-processing steps while authenticating access token.
Thanks in Advance.
Check out Json Web tokens. Using them allows your server to become stateless (not saving any sessions on memory).
Its concept is to pass a digital signed token, for every request, and checking that the signature is correct for integrity.
Json Web Encryption also can encrypt sensitive data along the token (such as user id).
This makes it very easy to work on a distributed environment
Check out this website: https://jwt.io/. There are some implementations in java and plenty of code examples to start with.
Some words about authentication with tokens
Once you are using JAX-RS, have a look at this answer that I wrote a while ago.
Your tokens can be any randon string persisted to some storage. On the other hand, JWT tokens allow you to have stateless authentication (no persistence). If you need to track the JWT tokens (to revoke them, for example), you must persist at least their identifier (the jti claim). A HashMap shouldn't be used to "persist" tokens (that's not a real persistence and it won't scale). Instead, consider a database like Redis.
To generate and parse JWT tokens, have a look this library created by Stormpath and maintained by a community of contributors. I currently use it in some applications and I can say with confidence that it works just fine and it's easy to use.
Keep reading for more details about the authentication process.
Authentication with tokens at a glance
In a few words, a token-based authentication follow these steps:
The client sends their credentials (username and password) to the server.
The server authenticates the credentials and generates a token.
The server stores the previously generated token in some storage along with the user identifier and an expiration date.
The server sends the generated token to the client.
In every request, the client sends the token to the server.
The server, in each request, extracts the token from the incoming request. With the token, the server looks up the user details to perform authentication and authorization.
If the token is valid, the server accepts the request.
If the token is invalid, the server refuses the request.
The server can provide an endpoint to refresh tokens.
Using JAX-RS to implement authentication based on tokens
The authentication starts when the server receives the hard credentials (username and password) of a user and exchanges them with a token that the client must send in each request:
#Path("/authentication")
public class AuthenticationResource {
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response authenticateUser(Credentials credentials) {
try {
// Authenticate the user using the credentials provided
String username = credentials.getUsername();
String password = credentials.getPassword();
authenticate(username, password);
// Issue a token for the user
String token = issueToken(username);
// Return the token on the response
return Response.ok(token).build();
} catch (Exception e) {
return Response.status(Response.Status.UNAUTHORIZED).build();
}
}
private void authenticate(String username, String password) throws Exception {
// Authenticate against a database, LDAP, file or whatever
// Throw an Exception if the credentials are invalid
}
private String issueToken(String username) {
// Issue a token (can be a random String persisted to a database or a JWT token)
// The issued token must be associated to a user
// Return the issued token
}
}
A filter will be used to extract the token from the HTTP request and validate it:
#Provider
#Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// Get the HTTP Authorization header from the request
String authorizationHeader =
requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
// Check if the HTTP Authorization header is present and formatted correctly
if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
throw new NotAuthorizedException("Authorization header must be provided");
}
// Extract the token from the HTTP Authorization header
String token = authorizationHeader.substring("Bearer".length()).trim();
try {
// Validate the token
validateToken(token);
} catch (Exception e) {
requestContext.abortWith(
Response.status(Response.Status.UNAUTHORIZED).build());
}
}
private void validateToken(String token) throws Exception {
// Check if it was issued by the server and if it's not expired
// Throw an Exception if the token is invalid
}
}
For further details, have a look at this answer.
JSON Web Token
JSON Web Token (JWT) is defined by the RFC 7519 and I think it fits really well for your needs.
It's a standard method for representing claims securely between two parties (in this situation, client and server). JWT is a self-contained token and enables you to store a user identifier, an expiration date and whatever you want (but don't store passwords) in a payload, which is a JSON encoded as Base64.
The payload can be read by the client and the integrity of the token can be easily checked by verifying its signature on the server.
To find some great resources to work with JWT, have a look at http://jwt.io.
And remember: when sending sensitive data over the wire, your best friend is HTTPS. It protects your application against the man-in-the-middle attack.
Tracking the tokens
You won't need to persist JWT tokens if you don't need to track them.
Althought, by persisting the tokens, you will have the possibility of invalidating and revoking the access of them. To keep the track of JWT tokens, instead of persisting the whole token, you could persist the token identifier (the jti claim) and some metadata (the user you issued the token for, the expiration date, etc) if you need.
There are many databases where you can persist your tokens. Depending on your requirements, you can explore different solutions such as relational databases, key-value stores or document stores.
Your application can provide some functionality to revoke the tokens, but always consider revoking the tokens when the users change their password. When persisting tokens, always consider removing the old ones in order to prevent your database from growing indefinitely.
You can combine both HashMap and database. In your case, HashMap can be used as a cache. The first time user was authenticated, access token information of this user should store to HashMap. The next APIs, we will check if the access token is exist in HashMap. If it exists, we use it to authenticate, if not we will query from database and store it to HashMap.
You need to expire access tokens in HashMap that was not used for a duration.
everybody.
Say, I have a web server and a client, which connects to it for the first time. The authentication mechanism is:
1) parse the client's UsernameToken element and retrieve its username, password and
nonce.
2) evaluate a hash: SHA2 (username + password + nonce)
3) check if a Data Base contains such a hash.
Let's assume that there is such a hash. The question is, how to know that the client is already authenticated, when it connects the second time?
Searching the DB is rather expensive, so I can't do it at every connect.
Saving the clients hash in memory will increase the performance, but how long should it present in such a registry and it seem to be a huge security hole.
Session parameter? But how can it be implemented in the web-services context?
Users log in to my BlackBerry app with a username and password provided at registration. My app connects to a Java Web Service that does all the logic.
How do I go about storing the password and username in a safe manner on my server? Everybody says salting and hashing, but I have no idea how to do this since I've never worked with it. How can I do this in Java?
How do I manage sending the password securely from the app to the server?
To store the credentials, one possibility is to use PBKDF2. A Java implementation (that I have not used) is available here. Run the password with the salt value through that and store the resulting hash data. The salt value is typically a newly generated random value (one for each password). This helps prevent dictionary attacks via rainbow tables (pre-computed tables of hashed passwords). Using java.security.SecureRandom is a possibility for generating those.
The client application should probably connect to the server using SSL/TLS. That will provide the encryption to protect the credentials when passed from client to your server application.
Edit Based on our conversation in the comments, it sounds as if the goal is not to use SSL. Assuming that is true and no other end-to-end communications encryption is planned, then it seems to imply that the security of the communications is not a high priority. If that is true, then maybe the described scheme for authenticating is sufficient for the application. Nonetheless, it seems worth pointing out the potential issues so you can consider them.
The proposed scheme (I think) is to send from the client to the server this value: Hash(Hash(password,origsalt),randomsalt). What this really means is that the password is effectively Hash(password,origsalt). If the attacker can get that information, then they can login as that user because they take that value and hash it with the new salt value to authenticate. In other words, if the database of hashed passwords is compromised, then the attacker can easily gain access. That somewhat defeats the purpose of salting and hashing the passwords in the first place.
Without SSL (or some other end-to-end encryption), there is the possibility of a man-in-the-middle attack. They can either listen in or even impersonate one end of the conversation.
Seems like your question has a few parts...
The most secure way to store the password in the database is to use a hash with a Salt + Pepper seed as described here. If you want to find a good way of implementing that specific technique in Java, try opening a new question.
I can see why it would make sense to encrypt a username/password hash prior to sending to the server, since SSL proxies can be a man-in-the-middle for that operation.
As a solution try creating a token in JSON or XML format that has the following properties:
Username.ToUpper() // Dont want this to be case sensitive
ExpiryDate (Say now plus 5 minutes)
Nonce (a random number that is saved on the backend to prevent replay attacks)
SHA 256 signature
Use the locally entered username and password to create a SHA256 signature, as it will be a constant. Use this signature to sign the JSON or XML you send to the server with each request.
In other words you're using a symmetric key based on the username and password, without sending it across the wire. Of course you may want to salt and pepper the generation of that symmetric key for more security.
That's all I got for a high level design, since I'm not intimately familiar with Java. Do share your links/code when you do find the answers.
So here's what I ended up doing:
package Utils;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.RandomStringUtils;
/**
*
* #author octavius
*/
public class SalterHasher {
private String salt;
private String pepper = "******************";
private String hash;
private String password;
public SalterHasher(String password, String username)
{
this.password = password;
salt = RandomStringUtils.random(40, username);
hash = DigestUtils.md5Hex(password + salt + pepper);
}
public String getHash(){
return hash;
}
/**
* #return the salt
*/
public String getSalt() {
return salt;
}
public String makeHash(String salt){
return DigestUtils.md5Hex(password + salt + pepper);
}
}
A very simple class that generates a salt and the hash for me and has a pepper included for added security, the makeHash() function I use for verification when the user logs in. In view of what I previously mentioned in the comments above I didn't end up using the verification process I proposed and chose to simply add the pepper to my server side code since hashing I believe would prove to be heavy on the BlackBerry device. Thanks again to those who helped me. Good discussions were had :)
I am using the JConsole to access my application MBeans and i use the the password.properties file. But as per the Sun's specification this file contains passwords in clear text formats only.
com.sun.management.jmxremote.password.file=<someLocation>/password.properties
Now i would want to encrypt the password and use it for the JMX user authentication from JConsole (the username and password fields in Remote section). I could use any pre-defined encryption logic or my own encryption algorithms.
Does anyone know of any such interception to change the plain text password to encrypted one so that the JMX Framework too knows about the encrypted password?
My Current password file:
guest guest
admin admin
With Encryption it should look like:
guest ENC(RjqpRYbAOwbAfAEDBdHJ7Q4l/GO5IoJidZctNT5oG64=)
admin ENC(psg3EnDei6fVRuqHeLwOqNTgIWkwQTjI2+u2O7MXXWc=)
You can use the configuration parameter com.sun.management.jmxremote.login.config in the management.properties file (see %JAVA_HOME%/lib/management/management.properties) to configure which Authenticator and LoginModule to use.
The default is the following:
JMXPluggableAuthenticator {
com.sun.jmx.remote.security.FileLoginModule required;
};
which reads plain text password file jmxremote.password. Since the com.sun.jmx.remote.security.JMXPluggableAuthenticator can be reconfigured
to use any LoginModule implementation, you are free to either choose an existing LoginModule or to implement your own
which uses encrypted password files.
To reimplement FileLoginModule, you should have a look at the attemptAuthentication(boolean) method, which
actually performs the authentication and which you probably are going to replace. Implement the javax.security.auth.spi.LoginModule interface
and use the given CallbackHandler (you will get it from the init() method) to ask for a username and password. Encrypt/hash the received password and compare it against the one read from your encrypted password file. Pseudo code:
public class EncryptedFileLoginModule implements LoginModule {
#Override
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map<String, ?> sharedState, Map<String, ?> options) {
this.subject = subject;
this.callbackHandler = callbackHandler;
}
public boolean login() throws LoginException {
attemptLogin();
if (username == null || password == null) {
throw new LoginException("Either no username or no password specified");
}
MessageDigest instance = MessageDigest.getInstance("SHA-1");
byte[] raw = new String(password).getBytes();
byte[] crypted = instance.digest(raw);
// TODO: Compare to the one stored locally
if (!authenticated) throw new LoginException();
return true;
}
private void attemptLogin() throws LoginException {
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("username");
callbacks[1] = new PasswordCallback("password", false);
callbackHandler.handle(callbacks);
username = ((NameCallback) callbacks[0]).getName();
user = new JMXPrincipal(username);
char[] tmpPassword = ((PasswordCallback) callbacks[1]).getPassword();
password = new char[tmpPassword.length];
System.arraycopy(tmpPassword, 0, password, 0, tmpPassword.length);
((PasswordCallback) callbacks[1]).clearPassword();
}
However, as this is already the server-side, the password would afaik be still transferred in plain text if you don't enforce
JMX over SSL. So, either enforce SSL or use another transport protocol mechanism which encodes the credentials before
transmitting them over the wire.
To conclude, it's perhaps much better to rely on existing authentication mechanisms provided by JAAS. If, for example,
you're running in a local Windows environment, you can easily use the NTLoginModule for auto-login. But it only works on local machine.
Create a file c:/temp/mysecurity.cfg:
MyLoginModule {
com.sun.security.auth.module.NTLoginModule REQUIRED debug=true debugNative=true;
};
Next, configure the jmxremote.access file to contain the usernames or roles you wish to grant access to your JMX server:
monitorRole readonly
controlRole readwrite ...
mhaller readonly
(I recommend to enable debug mode until it works. You will see all the user names, domain names and group names when a user tries to log in)
Set the following JVM arguments for your server:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=8686
-Dcom.sun.management.jmxremote.authenticate=true
-Dcom.sun.management.jmxremote.ssl=true
-Djava.net.preferIPv4Stack=true
-Djava.security.auth.login.config=c:/temp/mysecurity.cfg
-Dcom.sun.management.jmxremote.login.config=MyLoginModule
Start up your application and try to connect using JConsole or VisualVM.
Note that JConsole, you will need to specify a username and a password, although it's not going to be used. Any password and any username will work.
The reason is because jconsole will try to authenticate with null username and null password, which is blocked explicitly.
VisualVM does a better job by using empty strings for username and password when none are entered by the user.
Also note that the NTLoginModule does not work when connecting remotely, i think you would have to use a more sophisticated login module,
but Sun already provides enough of them:
com.sun.security.auth.module.Krb5LoginModule: Authenticates users using the Kerberos protocols
com.sun.security.auth.module.LdapLoginModule: (new in Java 6): Performs authentication against an LDAP server by specifying technical connection user
com.sun.security.auth.module.JndiLoginModule: Performs authentication against an LDAP server registered in the JNDI context
com.sun.security.auth.module.KeyStoreLoginModule: Authenticates users by using a Java Keystore. Supports PIN or smart card authentication.
You will want to have a look at the LdapLoginModule