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

[FEATURE] Add CAPTCHA to login and password reset pages #680

Open
adambuttrick opened this issue Jul 16, 2024 · 7 comments · May be fixed by #839
Open

[FEATURE] Add CAPTCHA to login and password reset pages #680

adambuttrick opened this issue Jul 16, 2024 · 7 comments · May be fixed by #839
Assignees
Labels
enhancement New feature or request

Comments

@adambuttrick
Copy link

adambuttrick commented Jul 16, 2024

Describe the problem you would like to solve
Our current login and password reset pages lack lockout mechanisms beyond WAF rate limits, making them potentially subject to automated attacks and potential brute force attempts. We need a way to enhance security and ensure that only genuine users can access these pages.

Describe the solution you'd like
Implementing a CAPTCHA system on both the login and password reset pages. We should confer with the Merritt service team, as they have already implemented this feature. Their experience could tell us:

  • The type of CAPTCHA that works best for our scale of service
  • Any implementation challenges they faced
  • Impact on legitimate login attempts and password resets

Who would benefit from this feature?

  • End Users: Increased security for their accounts
  • Dev Ops: Reduced risk/need to manage automated attacks
  • IAS: Better overall security
@adambuttrick adambuttrick added the enhancement New feature or request label Jul 16, 2024
@sfisher sfisher self-assigned this Jan 28, 2025
@sfisher
Copy link
Contributor

sfisher commented Jan 30, 2025

I've talked with Terry about how they did it in Merritt and they were very happy with the results.

They're using the AWS Web Application Firewall (WAF) to do the CAPTCHA as described at https://docs.aws.amazon.com/waf/latest/developerguide/waf-captcha-and-challenge.html and some related pages.

What it does is you set up some configured endpoints for protection and it adds the CAPCHA for you in AWS. He suggested the "silent challenge" mode which doesn't always pop up a thing to fill out but reduced their traffic from bots significantly.

We'd want to protect POST "/login" and POST "/account/pwreset" I believe.

I'm not sure exactly how we configure our WAF and will check in with Ashley.

@adambuttrick
Copy link
Author

Guide on updating the WAF rules, provided by Ashely in 2025/02/11 stand up:

https://ucopedu.atlassian.net/wiki/spaces/UC3/pages/45446923/WAF

@sfisher
Copy link
Contributor

sfisher commented Feb 19, 2025

Ashley will be updating the uc3-aws2023-ops-cdlib.org server with the functions for working with the waf rules. Currently can't easily do work on this without those waf functions present.

@sfisher sfisher linked a pull request Feb 20, 2025 that will close this issue
@sfisher
Copy link
Contributor

sfisher commented Feb 24, 2025

These rules are in place on ezid-stg and have been since 2/19 or so. Here is some historical information about traffic to login and other pages from the first week. Many requests get blocked by other WAF rules, but there are some that go through.

I tested by running a script to hit the server repeatedly (see PR) and it began blocking after about 150 requests in a short time.

I'm not sure how useful this data really is and we're not seeing huge problems on stage, but maybe on production this will be more significant change.

Image

Image

Image

Image

Image

Image

Image

@sfisher
Copy link
Contributor

sfisher commented Feb 28, 2025

I've spent a bunch of time trying to verify these rules and I get similar results as above on stage since sending many requests triggers other rate limits we already have in place. So we're getting blocking but by other existing rules since these are placed at the end of the rules.

I could move them to the top of the rules if we want to see them happening, but I've also re-verified they are in place.

# dump the rules
~/bin/modify-waf-rules.py uc3-ezidui-stg-waf -o uc3-ezidui-stg-waf.rules_output.$(date +"%Y%m%d").yaml

# look in text for the rules
- Action:
    Block: {}
  Name: rate-limit-login
  Priority: 16
  Statement:
    RateBasedStatement:
      AggregateKeyType: IP
      EvaluationWindowSec: 300
      Limit: 100
      ScopeDownStatement:
        AndStatement:
          Statements:
          - RegexMatchStatement:
              FieldToMatch:
                UriPath: {}
              RegexString: ^\/(login|account\/pwreset)
              TextTransformations:
              - Priority: 0
                Type: NONE
          - ByteMatchStatement:
              FieldToMatch:
                Method: {}
              PositionalConstraint: EXACTLY
              SearchString: !!binary |
                VUU5VFZBPT0=
              TextTransformations:
              - Priority: 0
                Type: NONE
  VisibilityConfig:
    CloudWatchMetricsEnabled: true
    MetricName: rate-limit-login
    SampledRequestsEnabled: true
- Action:
    Challenge: {}
  Name: silent-challenge
  Priority: 17
  Statement:
    AndStatement:
      Statements:
      - RegexMatchStatement:
          FieldToMatch:
            UriPath: {}
          RegexString: ^\/(login|account\/pwreset)
          TextTransformations:
          - Priority: 0
            Type: NONE
      - ByteMatchStatement:
          FieldToMatch:
            Method: {}
          PositionalConstraint: EXACTLY
          SearchString: !!binary |
            UjBWVQ==
          TextTransformations:
          - Priority: 0
            Type: NONE
  VisibilityConfig:
    CloudWatchMetricsEnabled: true
    MetricName: silent-challenge
    SampledRequestsEnabled: true

There aren't errors in the WAF rule format since it does checking when updating them and also, egregious problems would likely cause other failures.

I think this is all OK, though we're sort of doing suspenders and belt with a lot of overlapping rules.

If we think these particular rules should be the top priority over other rate limits or rules then I can rearrange and retest.

BTW, easy to test with something like:

for i in {1..50}; do curl -X POST https://ezid-stg.cdlib.org/account/pwreset -d '{}' & done

I also have a python script and PR that does something similar, but perhaps may allow a bit easier control.

@adambuttrick
Copy link
Author

adambuttrick commented Mar 4, 2025

@sfisher I don't think we need to prioritize these rules over the existing, but am also fine with the overlap for the sake of being especially cautious. We can always rationalize/reconcile later.

If the Python script is excessive, can we add the curl version to the notes on your pull request?

https://github.com/CDLUC3/ezid-docs-internal/pull/15/commits/fccfdfc667e9afa2b234db4720d10f0133284d39

@sfisher
Copy link
Contributor

sfisher commented Mar 4, 2025

Ok. I modified the rule to have the SearchString unencoded as POST or GET and it works. IDK why guides (and the Merritt existing rules) have them encoded. I also reduced the rate limit for these specific endpoints since people shouldn't need to log in and out repeatedly or frequently. It makes me wonder it the rules are really working for Merritt.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants