Cryptographic Captcha Cookie Protection

My company's CRM system uses a tracking system every time I log in and to use certain administrative functions. The original implementation kept the current captcha value for the server side session variable.

Now we need to repurpose this to store all the necessary conversion validation information in the hashed client cookie. This is due to the parent IT policy, which is designed to reduce overhead by prohibiting the use of sessions for users who have not yet authenticated with the application. Thus, the authentication process itself is not allowed to use server-side stores or sessions.

The design was a bit of a group design and I have doubts about its overall effectiveness. My question is, can anyone see any obvious security issues with the implementation shown below and this is too devoid of overkill or undersupply?

EDIT: Further discussion led to an updated implementation, so I replaced the original code with the new version and edited the description to talk to that version.

(The code below is a kind of pseudocode, the original uses some idiosyncratic libraries and a deprecation framework that makes it difficult to read. Hopefully this style is easy enough to understand.)

// Generate a "session" cookie unique to a particular machine and timeframe
String generateSessionHash(timestamp) {
    return sha256( "" 
        + (int)(timestamp / CAPTCHA_VALIDITY_SECONDS)
        + "|" + request.getRemoteAddr() 
        + "|" + request.getUserAgent() 
        + "|" + BASE64_8192BIT_SECRET_A
    );
}

// Generate a hash of the captcha, salted with secret key and session id
String generateCaptchaHash(captchaValue, session_hash) {
    return sha256( ""
        + captchaValue
        + "|" + BASE64_8192BIT_SECRET_B
        + "|" + session_hash
    );
}

// Set cookie with hash matching the provided captcha image
void setCaptchaCookie(CaptchaGenerator captcha) {
    String session_hash = generateSessionHash(time());
    String captcha_hash = generateCaptchaHash(captcha.getValue(), session_hash);
    response.setCookie(CAPTCHA_COOKIE, captcha_hash + session_hash);
}

// Return true if user input matches the cookie captcha hash
boolean isCaptchaValid(userInputValue) {
    String cookie = request.getCookie(CAPTCHA_COOKIE);
    String cookie_captcha_hash = substring(cookie, 0, 64);
    String cookie_session_hash = substring(cookie, 64, 64);
    String session_hash = generateSessionHash(time());
    if (!session_hash.equals(cookie_session_hash)) {
        session_hash = generateSessionHash(time() - CAPTCHA_VALIDITY_SECONDS);
    }
    String captcha_hash = generateCaptchaHash(userInputValue, session_hash);
    return captcha_hash.equals(cookie_captcha_hash);
}

      

Concept:

  • "session_hash" is designed to prevent the use of the same cookie on multiple computers and to provide a period of time after which it becomes invalid.
  • Both "session_hash" and "captcha_hash" have their own secret salt keys.
  • These keys BASE64_8192BIT_SECRET_A and _B are parts of the RSA private key stored on the server.
  • captcha_hash is both secret and session_hash salted.
  • Separators are added that use client-supplied data to avoid splice attacks.
  • "captcha_hash" and "session_hash" are stored in the client side cookie.

EDIT: re: Kobi Thanks for the feedback!

(I would answer in the comments, but it doesn't seem to accept the formatting that works in the questions?)

Every time they access the login page, the captcha is replaced; However, this suggests that they don't just re-submit without reloading the login form page. The session uses an expiration time to accomplish this task. We could also add a nonce to the login page, but for that we also need server-side session storage.

As per Kobe's suggestion, the hashed data now includes an expiration date, but the consensus is to add it to session_hash instead, as it's intuitive for a timed out session.

This idea of ​​hashing some data and including another hash in that data seems suspicious to me. Is there any benefit, or are we better off with one hash containing all the relevant data (time, IP, User-agent, Captcha value and secret key). In this implementation, we are basically talking the user-side hashed plaintext.

Questions:

  • Are there any obvious disadvantages?
  • Are there any subtle flaws?
  • Is there a more reliable approach?
  • Salting a hash with a different hash helping something?
  • Is there a simpler and equally reliable approach?

New question:

I personally think we'd better leave it as a server session; can anyone point me to any documents or articles proving or refuting the inherent risk of sending all verification data only to the client side?

+2


source to share


1 answer


Assuming there is no other security than stated here:
It seems an attacker can solve the captcha once and save the cookie.
Then it has its own constant session_hash

and captcha_hash

. Nothing stops her from sending the same cookie with the same hashed data - possibly breaking your system.
This can be avoided by using time

as a part captcha_hash

(you need to round it to an even time, maybe a few minutes - and check two options - current time and previous)

To correct, you said:

"session_hash" is intended to prevent the use of the same cookie on multiple machines.

It's true?
On isCaptchaValid

you do String session_hash = substring(cookie, 64, 64);

- that is: you rely on the data in the cookie. How can you tell that it was not copied from another computer? - you are not yet hashing the client data to confirm this (you actually have a random number, so it might not be possible). How can you tell about this new request and have not been used?



I understand that captcha is replaced by every login, but how can you know when the request was made? You are not checking the new captcha for isCaptchaValid

- your code will still check the request, even if it does not match the displayed image.
Consider the following scenario (could be automated):

  • Eve opens the login page.
  • Receives a new cookie and a new captcha.
  • Replaces it with her old cookie with her old cptcha hashed data.
  • Send the old cookie and userInputValue

    with the old captcha word.
  • With this input isCaptchaValid

    checks request - captcha_hash

    , session_hash

    , userInputValue

    and BASE64_8192BIT_SECRET

    are the same as on the first request.

By the way, on most systems you will need a nonce anyway to avoid XSS and also fix this problem.

+3


source







All Articles