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

LG-229 Add reCAPTCHA to account creation and password reset screens #2136

Merged
merged 2 commits into from
May 8, 2018

Conversation

stevegsa
Copy link
Contributor

@stevegsa stevegsa commented May 2, 2018

Why: To prevent bots from creating accounts or abusing the mail system.

How: By incorporating the recaptcha gem (invisible option) and logging three conditions upon submit: captcha valid, captcha present (the user can click on the page to make the captcha disappear and the token won't be sent), and captcha enabled (our system level toggle). We have also added an A/B test service which allows us to slow roll the feature while gathering statistics about impact. Effectively you can set the percentage of time you want the feature enabled through the recaptcha_enabled_percent feature flag. This service can easily be added to any feature flag for A/B testing. The state of the test (enabled/disabled) is stored in session and there is an option to have it reset at the beginning of each test.

Hi! Before submitting your PR for review, and/or before merging it, please
go through the following checklist:

  • For DB changes, check for missing indexes, check to see if the changes
    affect other apps (such as the dashboard), make sure the DB columns in the
    various environments are properly populated, coordinate with devops, plan
    migrations in separate steps.

  • For route changes, make sure GET requests don't change state or result in
    destructive behavior. GET requests should only result in information being
    read, not written.

  • For encryption changes, make sure it is compatible with data that was
    encrypted with the old code.

  • For secrets changes, make sure to update the S3 secrets bucket with the
    new configs in all environments.

  • Do not disable Rubocop or Reek offenses unless you are absolutely sure
    they are false positives. If you're not sure how to fix the offense, please
    ask a teammate.

  • When reading data, write tests for nil values, empty strings,
    and invalid formats.

  • When calling redirect_to in a controller, use _url, not _path.

  • When adding user data to the session, use the user_session helper
    instead of the session helper so the data does not persist beyond the user's
    session.

  • When adding a new controller that requires the user to be fully
    authenticated, make sure to add before_action :confirm_two_factor_authenticated.

@stevegsa
Copy link
Contributor Author

stevegsa commented May 2, 2018

Screenshots:

screen shot 2018-05-02 at 3 43 40 pm

screen shot 2018-05-02 at 4 25 25 pm

If google thinks you are a bot:

screen shot 2018-05-01 at 10 47 14 am

@stevegsa stevegsa force-pushed the stevegsa-recaptcha branch 5 times, most recently from 0851e2e to c906f69 Compare May 4, 2018 00:12
@stevegsa stevegsa force-pushed the stevegsa-recaptcha branch from 3029a8f to 741e792 Compare May 4, 2018 03:31
@stevegsa stevegsa force-pushed the stevegsa-recaptcha branch 2 times, most recently from 7c9ff9a to 1e1445c Compare May 4, 2018 04:05
@stevegsa stevegsa force-pushed the stevegsa-recaptcha branch 2 times, most recently from 6491cab to 946c70a Compare May 4, 2018 14:32
Copy link
Contributor

@davemcorwin davemcorwin left a comment

Choose a reason for hiding this comment

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

In general LG, some organizational comments.

@percent_on = percent_on.to_s.to_i
end

def enabled?(session, reset)
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible to separate checking whether the feature is enabled and enabling the feature? Changing the state as a side effect of seeing if its enabled it seems unexpected to me (unless I'm measuring its quantum state...) Also, this looks like the only case where FeatureManagement is looking to any logic besides env variables to see if a feature is enabled and that may be confusing.

It seems like there are 2 levels here

  1. whether the recaptcha feature is enabled for the environment (controlled by FeatureManagement)
  2. whether the session requires the recaptcha (controlled by AbTest`)

What do you think about asking AbTest if its enabled and AbTest asking FeatureManagement instead of the other way around? Then maybe enabling it explicitly as a second step?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The enabled? method for the Ab test is really just deciding whether to run A or B so it is somewhat misleading. I'm not in favor of AB Test calling FeatureManagement because I wanted to leave it loosely coupled (though I did think about it...). The AB test service can be used standalone without any dependency on our FeatureManagement config.

@@ -194,4 +194,16 @@ def analytics_exception_info(exception)
exception_class: exception.class.name,
}
end

def validate_recaptcha
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm wondering why this logic belongs in the ApplicationController instead of as a concern or super class for the form objects. It seems to me that its really just another part of the form that needs to be validated, and this would simplify the implementation and the tests a bit since you won't have to alter the controllers and can test most of the functionality at the form object level instead of at the controller level.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The form objects isn't a good option because verify_recaptcha is placed in ActionController::Base by the gem. The reason why I chose ApplicationController over a concern is because I thought eventually Recaptcha would be part of most pages.

Copy link
Contributor

Choose a reason for hiding this comment

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

I would think we would only need it for unauthenticated pages. Also, what does recaptcha provide that rate limiting with Rack Attack doesn't?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Spinning through IPs in a block, spinning through anonymous IPs, etc.

Copy link
Member

Choose a reason for hiding this comment

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

👍 to just putting it where we need it for now. It isn't hard move it into the application controller later if we need to.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. Adding it to a separate concern right now.

@davemcorwin
Copy link
Contributor

davemcorwin commented May 7, 2018 via email

@davemcorwin
Copy link
Contributor

davemcorwin commented May 7, 2018 via email

@stevegsa
Copy link
Contributor Author

stevegsa commented May 7, 2018

@davemcorwin I see what you are saying wrt the featuremanagement and abtest. It would allow me to mock out a single behavior and not run through so many combinations. I did think about it but I'd still be stuck with providing some type of feature spec so I tried to mock out everything at the lowest possible level to sufficiently test all the code paths.

Copy link
Contributor

@davemcorwin davemcorwin left a comment

Choose a reason for hiding this comment

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

Also, it looks like if recaptcha fails, it will fail the form validation, but we're not capturing the errors (except in analytics). Do we want to include any of this feedback to users? Will this be confusing when debugging/testing the forms?

@stevegsa
Copy link
Contributor Author

stevegsa commented May 7, 2018

The flash/errors are hidden because the recaptcha will popup again and obscure them. Essentially their error is seeing the recaptcha again.

@stevegsa
Copy link
Contributor Author

stevegsa commented May 7, 2018

wrt the featuremanagement and abtest: After looking at my code again the featuremanagement method was that single behavior fronting the mocks. Originally there was no dependence on the FeatureManagement since I was simply reading in an environment variable in Figaro.

@stevegsa
Copy link
Contributor Author

stevegsa commented May 7, 2018

We can't add include Recaptcha::Verify wherever we need it because it's pulling from request and params directly

@davemcorwin
Copy link
Contributor

davemcorwin commented May 7, 2018 via email

**Why**: To prevent bots from creating accounts or abusing the mail system.

**How**: By incorporating the recaptcha gem (invisible option) and logging three conditions upon submit: captcha valid, captcha sent (the user can click on the page to make the captcha disappear), and captcha enabled (our system level toggle).
@stevegsa stevegsa force-pushed the stevegsa-recaptcha branch from 6d8a3d7 to 289b57b Compare May 8, 2018 17:18
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.

4 participants