Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/captcha repeater vulnerability #427

Merged

Conversation

ivanmrsulja
Copy link
Member

@ivanmrsulja ivanmrsulja commented Nov 22, 2023

VIVO GitHub issue: Mitigate vulnerability of Captcha feature
VIVO PR

What does this pull request do?

This PR mitigates vulnerability of captcha feature by introducing new methods of challenge generation: nanocaptcha and Google reCAPTCHA.

What's new?

A CaptrchaServiceBean is created which can both provide and validate text-based challenges as well as provide validation services for Google reCaptcha through Google API. I also included a configuration for which captcha method is used so you can use both methods interchangeably (just change configuration options).

How should this be tested?

Unit tests for CaptchaServiceBean are created. If you want to test manually, simply run the application and follow instructions on how to configure each captcha method (instructions are available in example.runtime.properties file).
Captcha is currently only used on /contact page. Keep in mind that you have to setup SMTP properties as well as default contact email for feedback form to be accessible.

Interested parties

@litvinovg @chenejac @brianjlowe

Copy link
Contributor

@chenejac chenejac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ivanmrsulja thanks for this contribution. Please check one my comment.

api/pom.xml Outdated Show resolved Hide resolved
Copy link
Contributor

@litvinovg litvinovg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR!
Please take a look at some comments I did and translation suggestions.
I tested self hosted captcha. It works well.
Recaptcha V2 works.
Recaptcha V3 doesn't work (image below)
I didn't found any notes on what Recaptcha version should be supported.
I think it should be documented or V3 fixed if that was expected to be working.
Screenshot from 2023-12-11 13-57-50

@ivanmrsulja
Copy link
Member Author

Thanks for the PR! Please take a look at some comments I did and translation suggestions. I tested self hosted captcha. It works well. Recaptcha V2 works. Recaptcha V3 doesn't work (image below) I didn't found any notes on what Recaptcha version should be supported. I think it should be documented or V3 fixed if that was expected to be working. Screenshot from 2023-12-11 13-57-50

Yes, in the requirements, it was stated that there should be an "I'm not a robot field" which is reCAPTCHA v2 implementation. V3 runs in the background and it is a pure JS API that returns a score (based on number and speed of the interactions with the webpage). That score is the indicator whether additional measures should be taken for each interaction, it is a supplementary library. I did not plan to encorporate this functionality but it is open for discussion on the next meeting.

ivanmrsulja and others added 18 commits December 11, 2023 17:37
@ivanmrsulja ivanmrsulja force-pushed the fix/captcha-repeater-vulnerability branch from 62fffeb to c195f60 Compare December 12, 2023 15:50
Copy link
Contributor

@litvinovg litvinovg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update comment in example.runtime.properties to mention that only re-captcha v2 keys are supported in this PR and VIVO PR as was discussed at the meeting on Tuesday.
I suggest to convert string values of captcha.implementation in Java code to static fields.
Also, the name for self hosted captcha can be better I think.
Maybe we could use implementation name, like nanocaptcha in case somebody in future decides to add another self hosted captcha implementation. Not sure it should be in upper case, lower case looks better to me.
@chenejac What is your opinion?

chenejac
chenejac previously approved these changes Dec 15, 2023
Copy link
Contributor

@chenejac chenejac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ivanmrsulja I have added a comment which reflects committers' meeting discussion. Please, take a look.

home/src/main/resources/config/example.runtime.properties Outdated Show resolved Hide resolved
Copy link
Contributor

@litvinovg litvinovg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please convert captcha implementation options to constants or enumerations throughout the PR. A few more comments in the code.

captchaImplSetting = "NANOCAPTCHA";
}

return CaptchaImplementation.valueOf(captchaImplSetting.toUpperCase());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it is better to test if implementation in property file is one of supported values first, then for all other cases: missing implemenation value, misspelled value; return NANOCAPTCHA?
Otherwise it should throw IllegalArgumentException if value is misspelled which should result in broken contact form I guess.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right about misspelled values, but I think that it is more intuitive to firstly check all error logic as guard cases and then have the desired logic after that, looks more readable to me. I will refactor the code to support misspelled values and to address a suggestion below, and after that, if you still think this is unintuitive I can change it as well 😄

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is improved to fall back to NANOCAPTCHA impl when misspelled configurations are provided.

Comment on lines 224 to 238
switch (captchaImpl) {
case RECAPTCHAV2:
if (CaptchaServiceBean.validateReCaptcha(captchaInput)) {
return true;
}
break;
case NANOCAPTCHA:
Optional<CaptchaBundle> optionalChallenge = CaptchaServiceBean.getChallenge(challengeId);
if (optionalChallenge.isPresent() && optionalChallenge.get().getCode().equals(captchaInput)) {
return true;
}
break;
case NONE:
return true;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if another captcha implementation is added?
Should there be a class for each captcha implementation?
Now class responsibilities seem a little bit mixed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can make a provider class for each implementation

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have refactored code and made providers for each implementation. ServiceBean only delegates requests to providers and is responsible for challenge persistence (in-memory).

Copy link
Contributor

@litvinovg litvinovg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default difficulty should be easy.
I tested nanocaptcha and recaptchav2, works fine.

home/src/main/resources/config/example.runtime.properties Outdated Show resolved Hide resolved
@litvinovg litvinovg self-requested a review January 9, 2024 15:10
Copy link
Contributor

@chenejac chenejac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ivanmrsulja well done

@chenejac chenejac merged commit 2df1164 into vivo-project:main Jan 10, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Mitigate vulnerability of Captcha feature
6 participants