Slow password history validation using BCrypt - bcrypt

We're using bcrypt to hash the users' passwords, and we store a list of the last 10 hashes to make sure they don't use the same password as the last 10 when they create a new one.
One issue we're running into is that checking the password history is a very slow process. The algorithm goes something like this:
// The user's entered password on the password change page
String rawPassword = ...
// For demonstration purposes, the password has passed all other validation measures
Boolean passwordIsValid = true;
// Loop through all the stored passwords we have for that user. We have a max of 10
for (String oldHashed: user.passwordHashHistory) {
// Must re-hash every time using the same salt as the one stored in history
// NOTE: SLLOOOWWWWW!
String newHashed = Bcrypt.hashPw(rawPassword, oldHashed);
// Now we can see if it's a match
if (newHashed.compareTo(oldHashed) == 0) {
// User is using one of the old passwords
passwordIsValid = false;
}
}
The above code works, but it can take 5-6 seconds on my workstation for one user to validate his password is changed. Can I do anything to mitigate this short of reducing the log rounds or beefing up the server?

The BCrypt algorithm was designed precisely to be slow, with the cost factor you can determine how much time is needed to calculate a password hash. This "slowness" is the only way to thwart brute-force attacks.
If there was a way to speed up this process, an attacker would surely make use of it. So no there is no way to make short cuts here.

Related

What is the difference when using KEYS and SCAN in a LUA script?

I am currently using the Redis, version:3.2.12 as a cache memory for my application: Spring Boot. I want to match a list of patterns and then delete them from Redis. I've opted to use LUA scripts and have come up with the following script.
local cursor='0';
local keysVar = {};
repeat
local scanResult = redis.call('SCAN', cursor, 'MATCH', ARGV[1], 'COUNT', 100);
local keys = scanResult[2];
for i = 1, #keys do
keysVar[i] = keys[i];
end;
cursor = scanResult[1];
until cursor == '0';
redis.replicate_commands()
redis.call('DEL', unpack(keysVar));
return keysVar ;
From what I've read the SCAN command was created to break up the blocking KEYS command which could present major issues when used in production. But, since I've decided to use LUA and Redis guarantees the script's atomic execution. While executing the script, all server activities are blocked during its entire runtime. Won't using KEYS and SCAN in an LUA script result in the same as both of them have a time complexity of O(N)?
So, what is the difference between using the above script vs, using
return redis.call('DEL', 'defaultKey', unpack(redis.call('KEYS', #keypattern)))
One more question. Why is the KEYS command regarded as deterministic, can't the number of keys returned change when let's say slave performs the KEYS command with a pattern? The reason given for the SCAN command to be non-deterministic is that the results returned may vary from master to slave. Can't the same be said for the KEYS too?
And since a SCAN uses a cursor, how is there a chance of the same key getting returned multiple times?
I am trying to delete a list of patterns using the Redis template.
private void clearCache(List<String> patterns) {
Resource scriptSource = new ClassPathResource("cleanup.lua");
RedisScript<String> redisScript = RedisScript.of(scriptSource, String.class);
patterns.forEach(pattern -> {
redisTemplate.execute(redisScript, Collections.emptyList(), pattern);
});
}
Is there a correct/recommended way to do so?
Won't using KEYS and SCAN in an LUA script result in the same as both of them have a time complexity of O(N)?
YES, they both have O(N) complexity. So you should NOT use either in production env.
So, what is the difference between using the above script vs, using...
The script with an unpacked keys result, might fail, if there's too many keys. Because, if I remember correctly, Redis has a limit on the byte-length of a command.
And since a SCAN uses a cursor, how is there a chance of the same key getting returned multiple times?
Because normally, the keyspace is dynamically during the scan, e.g. new key added, old key expired or removed.

Only one User using entire web application at a time - Spring boot

In spring boot application only one user should be using the certain page at a time (let's call it home.jsp). Another users should be redirected to different page(let's call it another_home.jsp) if they appear when accessing that same url. User doesn't login and just uses the application as it is. Any policy can be used for home.jsp could be first-come-first-serve or any other.
If more than one users are using application at a time only one user should be using home.html and all rest of the others should be using another_home.jsp.
As no login is needed in the application I believe I need anonymous sessions. Also, session needs to be expired after some time of inactivity. I've searched spring security but couldn't find anything.
I think that you don't even need spring security. Simple http session will work too. As far as I can see you just want to allocate the stream to one user and for that you need first user's session id which you can compare against whenever the requests come again. So store session id and expire after some timeout with some Time object or Date object.
In properties
server.servlet.session.timeout = 600 // 10 minutes
Something like this
private String currSessionId = null;
private Date lastDate = new Date();
private Integer TIMEOUT = 600000; // 10 minutes
public String loadHomePage(Model model) {
if(currSessionId!=null && new Date().getTime()- lastDate.getTime()>TIMEOUT){
currSessionId = null;
}
if(currSessionId==null){
currSessionId = session.getId();
lastDate = new Date();
return "home";
}else{
if(session.getId().equals(currSessionId)){
return "home";
}else{
return "another_home";
}
}
}
This is as simple as it gets when you don't have logged in users to manage and also don't need to remember previous state where user left off. Let me know if it helps.
You need to create a serverside state that is either empty or stores the identifier of the visitor that is currently claiming /home.jsp.
This could be a field on a singleton Bean, or an entity in the database.
It has to expire automatically, or it will prevent new visitors forever to make a claim.
As long as the state is empty, the first visitors identifier will be stored in this state.
And from that moment on, you will redirect all other visitors to another_home.jsp
So the Controllers Code would be something like this
if(visitorHoldsTheClaim()) {
return "home.jsp"
} else if (noClaimActive()) {
createClaimForVisitor();
return "home.jsp"
} else {
return "redirect:/another_home.jsp"
}
Depending on your implementation, these methods will do different things.
I'd usually recommend against serverside session state (more about this in Roy Fieldings Dissertation),
but for your use case, you need a way to identify a visitor over many requests.
A session would certainly be a very simple way to achieve this.
You can at least minimize session usage by only creating one session at a time - the one for the visitor that holds the claim.
In this case you'd never have more than one open session, and the visitor that owns the session is the visitor that holds the claim.
So in this case, the implementation would be be something like this:
if(currentUserHasASession()) { // checks if the current user has a session, but !!!does not create a new session if it does not exist!!! careful, HttpServletRequest.getSession(true) would create it!
return "home.jsp"
} else if (serverHasNoSessions()) { // https://stackoverflow.com/questions/49539076/how-can-i-get-a-list-of-all-sessions-in-spring
createSessionForUser(); // HttpServletRequest.getSession(true)
return "home.jsp"
} else {
return "redirect:/another_home.jsp"
}
Keep in mind that this only works if you do not create Sessions in another place.
So you have to configure Spring Boot/Spring Security to not create Sessions. How to make spring boot never issue session cookie?
Also keep concurrency in mind. For example, if you had only one server instance, you could put this code into a synchronized method to avoid two visitors creating a claim at the same time.
So... first of all, this sounds like a bad idea. I would be curious why you would need such an unusual behavior. There might be more sensible approaches for it.
Like Gregor said, the redirect code part is rather straightforward:
if(pageLock.getUser() == null) {
pageLock.setUser(user);
}
if(user.equals(pageLock.getUser())) {
return "home.jsp"
} else {
return "redirect:/another_home.jsp"
}
What is actually more tricky is the part when "expiring" the lock. It's likely the user will simply close the browser and not click on "logout" (or whatever), leaving the lock forever. On the other extreme, the user might be gone for a lunch break but its browser still has the page open for hours.
So that's the first thing you wanna add: some keep-alive mechanism on the page, regularly prolonging the lock, and some expiration checker, releasing the lock if nothing was received for a while.
...but like I said in the beginning, the whole thing sounds fishy.

Adobe Analytics - Force a session/userID refresh

We have a website that can be viwed from a kiosk in a shop.
When the inactivity is above 2 minutes, the site returns to the home.
Anyone knows how to refresh the session when this appens?
It could also serve make a refresh of the user id, but I don't know how it works.
I'm going to assume you are talking about Adobe Analytics javascript library and not the Android/iOS SDK, based on your tagging and lack of mention of it. If your kiosk is in fact using Android or iOS SDK, then please comment and I can update with instructions for that.
Adobe Analytics javascript library does not currently offer a direct method to force refresh an Adobe Analytics session/userID. However, you can effectively do it by explicitly setting s.visitorID yourself, which will override the default generated by the library.
So, when you want to start a new session, you can pop s.visitorID with for example the current timestamp:
s.visitorID = (new Date()).getTime().toString();
Or maybe you already have a "session" id you generate that you can use, instead.
Note: with this method, you must set s.visitorID (with the same value) for every hit for the duration of your session. So in practice, you would really do something more along the lines of generate the new value at start of session, put the value in a cookie, and put s.visitorID in s_doPlugin but it reads the cookie value.
Note: This will effectively make your visits and visitors metrics the same. Which is to be expected with a publicly shared device, but just mentioning it in case it comes up later.
pseudocode:
function startNewSession() {
// use whatever cookie writing utility you have to
// set a cookie named visitorID set to the generated
// value. In practice, the expiration doesn't really
// matter as long as it's something longer than
// your average session. Just setting it to default
// session expiration should be okay
var visitorID = (new Date()).getTime().toString();
setCookie('visitorID',visitorID);
}
// in your existing logic that times out returning
// home after 2 minutes of inactivity, call the function
// to generate a new id
startNewSession();
// this is AA's s_doPlugins callback function. This may look
// slightly different, maybe defined as s_doPlugins and then assigned
// to s.doPlugins, depending on what AA lib version you are using.
// This is AA's callback function that gets called whenever
// an s.t or s.tl call is made
s.usePlugins=true;
s.doPlugins=function(s) {
// make sure visitorID variable is addedto linkTrackVars
// so it gets 'registered' for s.tl calls.
s.linkTrackVars='visitorID';
// explicitly set the visitorID with the cookie, using
// whatever cookie reading utility you have.
s.visitorID=readCookie('visitorID');
}

How do I generate a unique token (for e-mail verification)?

I want to implement a system that after user signs up, user will receive an email includes a link to verify this email is for that user.
The way I generate the token for verifying the email is like this:
import (
"crypto/rand"
"encoding/base64"
)
func generateToken() (string, error) {
b := make([]byte, 35)
_, err := rand.Read(b)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(b), nil
}
But what I want to ask is if this method is OK? How to make all the token generated by this method is unique ?
What is the normal way to implement this system ?
Please give me some ideas and tell me if this method of generating token is good.
Thanks.
Check out https://pkg.go.dev/github.com/google/uuid#NewRandom.
And you may want to consider storing this in a database with the email address and perhaps an expiry date / time so that the verification doesn't stay there forever. You may only want to allow people to verify within 24 hours, or 7 days and so on. Have another job that periodically cleans expired and non-verified emails.
Two points:
No, the method as presented won't guarantee them to be unique.
You don't need to have all your tokens to be unique.
To expand on these points…
You're dealing with a set of outstanding verification requests.
That is:
A request is made by the user;
You generate a unique verification token and store it into some presistent database. This is needed in order for verification to work anyway.
The user receives your e-mail and clicks that link from it which contain your token. At this point you remove the information about this pending verificaton request from your persistent storage.
As you can see, at any given time you only have several outstanding verification requests. Hence this situation has two important properties:
You only need the tokens of these outstanding requests be different from one another. It's OK to have a verification token to be the same as that of some past (or future) request.
Your tokens have to be hard-to-guess (obviously). I'm sure you already understand that.
So, the approach to generating a new token is as follows:
Generate something hard-to-guess.
Compare it with the tokens bound to the outstanding/pending verification requests persisted in your storage.
If you find an outstanding request with the same token, you have a collision so go to step (1) and repeat.
Otherwise the token is OK so proceed with it and persist the data about this request.
Once the request passed verification, remove it from your storage.
Exact algorythm for generating tokens does not matter much. I'd say an UUID or something looking like SHA-256/512 calculated over some random data is OK.

Most efficient way of authorizing users over different pages on my site?

I have only ever made single page webapps in the past; with these, as soon as a user connected, I would read the password hash stored in their cookies and match it to the value stored in my database to determine if the user was already logged in.
I am now wanting to make a site with multiple web pages though, and I have just realized that it would required querying the database every time a user goes to a new page; this seems extremely inefficient to me. Is there any better way to maintain an ongoing session with a client without straining my database/server in the process?
Take a look at using a session object Eg HttpContext.Session["UserAuth"] = true;
When you authenticate the user on your first page Eg Login, you can then create a session like in the example above. Then once you redirect to the next page, just check to see if the session does indeed exists and is valid.
Checking session:
if(HttpContext.Session["UserAuth"] != null)
{
if(HttpContxt.Session["UserAuth"].toString() == "true")
{
//Session is valid and user is logged in.
}
else{
//Session is invalid and user is not logged in.
}
}
So each page you want to check if the user is valid you can do the above check. As long as you have created the session on the first page at time of database authentication.
Please note the above code is just to give you an idea of how you can do this.
"UserAuth" is simply a the name you give to the Session that you are storing. It can be absolutely anything. The value you are storing in the Session in this case is 'true'.
So when you retrieve the value of the Session you simply get 'true', meaning the user is logged in.
When you log the user out for example you can change the value of the session "UserAuth" to false in the same manner in which you originally created it.
Eg
HttpContext.Session["UserAuth"] = false;

Resources