Page MenuHomePhabricator

Allow Stewards to enable 'emergency CAPTCHAs' for anonymous IP edits
Open, MediumPublic

Description

In the recent botnet editing attack, one of the original reasons that the wiki community escalated to SRE was that enabling the 'emergency CAPTCHA' functionality for anonymous IP edits requires a configuration push.

Currently this is implemented by editing $wmgEmergencyCaptcha in InitialiseSettings.php, like this patch.

There was broad agreement afterwards from both involved WMF staff and from responders in the community that it would be ideal if Stewards could enable this themselves, without having to escalate to someone with deploy access.

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes

Shame this couldn't really use an opt-in wiki set—that kind of functionality would be great though 😁

Shame this couldn't really use an opt-in wiki set—that kind of functionality would be great though 😁

Why couldn't it?

$emergencyCaptchaWikiSet = \MediaWiki\Extension\CentralAuth\WikiSet::newFromName( 'emergency-captcha-wikis' );
if ( $emergencyCaptchaWikiSet !== null ) {
	$wikisToEnable = $emergencyCaptchaWikiSet->getWikis();
	foreach ( $wikisToEnable as $wiki ) {
		$wmgEmergencyCaptcha[$wiki] = true;
	}
	unset( $wikisToEnable );
	unset( $wiki );
}
unset( $emergenceyCaptchaWikiSet );

any time a wikiset is defined with the name 'emergency-captcha-wikis', whether it is opt-in or opt-out, if this is added to CommonSettings.php it will turn on emergency captcha on those wikis. It should be fairly performant, since the wiki sets are cached indefinitely and only purged when they change

Shame this couldn't really use an opt-in wiki set—that kind of functionality would be great though 😁

Why couldn't it?

I'm not sure if I like a pattern of wiki sets with "magical" properties not configured via or visible in the UI.

$emergencyCaptchaWikiSet = \MediaWiki\Extension\CentralAuth\WikiSet::newFromName( 'emergency-captcha-wikis' );
if ( $emergencyCaptchaWikiSet !== null ) {
	$wikisToEnable = $emergencyCaptchaWikiSet->getWikis();
	foreach ( $wikisToEnable as $wiki ) {
		$wmgEmergencyCaptcha[$wiki] = true;
	}
	unset( $wikisToEnable );
	unset( $wiki );
}
unset( $emergenceyCaptchaWikiSet );

any time a wikiset is defined with the name 'emergency-captcha-wikis', whether it is opt-in or opt-out, if this is added to CommonSettings.php it will turn on emergency captcha on those wikis. It should be fairly performant, since the wiki sets are cached indefinitely and only purged when they change

CR-1 as too complicated:

if (
	$wmgEnableEmergencyCaptcha
	// if we're hardcoding things, I'd prefer hardcoding an ID instead of a name since it's harder to change by accident
	|| \MediaWiki\Extension\CentralAuth\WikiSet::newFromId( 42 )->inSet( WikiMap::getCurrentWikiId() )
) {
	// do what's currently in the `if ( $wmgEnableEmergencyCaptcha )` block
}

Although I'm not sure if you can access the database or caches when evaluating CS.php since the settings needed for that aren't fully registered yet.

A better solution would be to add a hook to ConfirmEdit that lets you specify if a given action should get a captcha prompt, at that point the config is surely fully loaded and it's also more efficient (less queries needed even for the cached values, since you don't need to evaluate that every page view).

The problem with using a hard coded id is that as far as I understand it, when all wikis are removed from a set it gets deleted, and the next time we want to use it a new set would be created with a different id, so this would require the same set to keep existing. On the other hand, doing it by name is just as unique but allows for recreation

(I'd like to note that the permissions for this task do not allow the subscribers to view it. Does it even need to be private, anyway?)

sbassett subscribed.

(I'd like to note that the permissions for this task do not allow the subscribers to view it. Does it even need to be private, anyway?)

Maybe due to it being sub-tasked from T302047? I don't think this needs to be private at all, so I'll go ahead and make it public.

sbassett changed the visibility from "Custom Policy" to "Public (No Login Required)".Mar 9 2022, 10:22 PM
sbassett changed the edit policy from "Custom Policy" to "All Users".

Given

... it would be ideal if Stewards could enable this themselves, without having to escalate to someone with deploy access.

This task is still about some kind of manual UI config mechanism, no? Like a new ConfirmEdit special page or a lightweight extension under metawiki that allowed for an easy way to set/unset $wmgEnableEmergencyCaptcha for various projects or groups of projects?

Given

... it would be ideal if Stewards could enable this themselves, without having to escalate to someone with deploy access.

This task is still about some kind of manual UI config mechanism, no? Like a new ConfirmEdit special page or a lightweight extension under metawiki that allowed for an easy way to set/unset $wmgEnableEmergencyCaptcha for various projects or groups of projects?

So the reason I suggested using CentralAuth global groups is that if we want to add new functionality like this somewhere else, it requires some thinking about how we should be storing the data - should there be a new database table to remember which wikis are configured to have it enabled? Easier to implement, but means a database read each time. Or, perhaps have the special page or whatever write to an included php file, like the installer does when setting the initial configuration - harder to implement, but lower performance impact since the settings would just be read as normal configuration.

Reusing CentralAuth means that there is already an interface, logging, database, etc. available, which I think would be easier and more stable than trying to write new handling from scratch.

jbond triaged this task as Medium priority.Mar 21 2022, 11:41 AM

Change 778678 had a related patch set uploaded (by Zabe; author: Zabe):

[mediawiki/extensions/ConfirmEdit@master] Add new ConfirmEditTriggersCaptchaHook

https://gerrit.wikimedia.org/r/778678

Change 778680 had a related patch set uploaded (by Zabe; author: Zabe):

[mediawiki/extensions/CentralAuth@master] Allow stewards to enable emergency captchas via a wikiset

https://gerrit.wikimedia.org/r/778680

Change 778678 merged by jenkins-bot:

[mediawiki/extensions/ConfirmEdit@master] Add new ConfirmEditTriggersCaptchaHook

https://gerrit.wikimedia.org/r/778678

Change 778680 abandoned by Zabe:

[mediawiki/extensions/CentralAuth@master] WIP: Allow stewards to enable emergency captchas via a wikiset

Reason:

Implementing emergency captchas through ca wikisets feels very hacky and it doesn't really bring a lot of benefits.

https://gerrit.wikimedia.org/r/778680

Change 814357 had a related patch set uploaded (by Zabe; author: Zabe):

[mediawiki/extensions/EmergencyCaptcha@master] Initial commit

https://gerrit.wikimedia.org/r/814357

I'm not sure if I like a pattern of wiki sets with "magical" properties not configured via or visible in the UI.

I need to agree with this.

Given

... it would be ideal if Stewards could enable this themselves, without having to escalate to someone with deploy access.

This task is still about some kind of manual UI config mechanism, no? Like a new ConfirmEdit special page or a lightweight extension under metawiki that allowed for an easy way to set/unset $wmgEnableEmergencyCaptcha for various projects or groups of projects?

So the reason I suggested using CentralAuth global groups is that if we want to add new functionality like this somewhere else, it requires some thinking about how we should be storing the data - should there be a new database table to remember which wikis are configured to have it enabled? Easier to implement, but means a database read each time. Or, perhaps have the special page or whatever write to an included php file, like the installer does when setting the initial configuration - harder to implement, but lower performance impact since the settings would just be read as normal configuration.

Reusing CentralAuth means that there is already an interface, logging, database, etc. available, which I think would be easier and more stable than trying to write new handling from scratch.

I have tried this a bit and the amount that can be reused is limited. And the work you need to invest to make this not some kind of "magical" property is also quite a bit, since you need to write some sort of UI for this and you also need to make the wikiset logs for this understandable. Implementing emergency captchas this way feels really hacky and I don't really like it. I prefer putting this into a "micro-extension". The database and logging needed for this is actually quite basic.

Change 818270 had a related patch set uploaded (by Zabe; author: Zabe):

[mediawiki/extensions/ConfirmEdit@master] Run ConfirmEditTriggersCaptchaHook under correct name

https://gerrit.wikimedia.org/r/818270

Change 818270 merged by jenkins-bot:

[mediawiki/extensions/ConfirmEdit@master] Run ConfirmEditTriggersCaptchaHook under correct name

https://gerrit.wikimedia.org/r/818270

akosiaris subscribed.

I am tentatively just removing SRE as I don't see something specifically actionable for SRE right now. Feel free to re-add.

Perhaps this good be a good Community Configuration candidate @KStoller-WMF?

The current emergency captchas are really an 'break glass in case of fire' style solution due to their various accessibility problems. So I'd much rather see time spent into either building better anti-abuse tools that make them not required or a more general solution for moving certain configuration from mediawiki-config.git to something that the community can self-manage, rather than building something specific for enabling the captchas only.

The current emergency captchas are really an 'break glass in case of fire' style solution due to their various accessibility problems. So I'd much rather see time spent into either building better anti-abuse tools that make them not required or a more general solution for moving certain configuration from mediawiki-config.git to something that the community can self-manage, rather than building something specific for enabling the captchas only.

Definitely, that's work already underway, T323811: [EPIC] Community configuration 2.0: Factor Community configuration out of GrowthExperiments, which is what Sam means by Community Configuration. Moving more general parts of AF configuration into that system ahead of, or at least at the same as, the emergency-CAPTCHA preference would, I agree, be better for both moderating and moderated users' experience.

This is all great long-term planning (seriously!) but is there a chance of making a stopgap, light-weight solution for just EmergencyCaptcha? Even if it's as simple as, I don't know, a page editable only by stewards (a few ways to implement that) that allows for a comma-separated list of wikis to have EmergencyCaptcha on on; have a script check it every 5 minutes or something. (Probably not ideal implementation, but just giving an idea of a fairly cheap implementation.)

This is all great long-term planning (seriously!) but is there a chance of making a stopgap, light-weight solution for just EmergencyCaptcha? Even if it's as simple as, I don't know, a page editable only by stewards (a few ways to implement that) that allows for a comma-separated list of wikis to have EmergencyCaptcha on on; have a script check it every 5 minutes or something. (Probably not ideal implementation, but just giving an idea of a fairly cheap implementation.)

I think @Zabe's WIP approach above (https://gerrit.wikimedia.org/r/814357) of creating a new EmergencyCaptcha extension is probably the fastest track for a more immediate, light-weight solution.

Zabe removed Zabe as the assignee of this task.Aug 2 2023, 4:45 PM

I don't have the time to work on it at the moment, feel free to adopt my patch or not if you prefer a different solution. :)

Change 814357 abandoned by Zabe:

[mediawiki/extensions/EmergencyCaptcha@master] Initial commit

Reason:

https://gerrit.wikimedia.org/r/814357

Code for T20110: Define AbuseFilter consequence to display a CAPTCHA is merged. One can configure AbuseFilter to invoke a showcaptcha action for edit requests for anonymous IP editors. The feature is currently disabled via a feature flag (wgConfirmEditEnabledAbuseFilterCustomActions) but it should be ready for re-enabling soon™. Does using AbuseFilter for showing CAPTCHAs to anonymous editors solve the problem statement of this task?

nb. no longer a steward, but just some hopefully helpful thoughts:

  • won't filters which hit an excessive number of edits be throttled? I think one which matches every IP edit is likely to hit this — admittedly, filter editors should try to make the filter more specific but this isn't always possible.
  • iff applied to Global Filters (so stewards etc. can manage this/it can target multiple projects), large projects will be opted out.

nb. no longer a steward, but just some hopefully helpful thoughts:

  • won't filters which hit an excessive number of edits be throttled? I think one which matches every IP edit is likely to hit this — admittedly, filter editors should try to make the filter more specific but this isn't always possible.

The implementation does not define the showcaptcha consequence as a "dangerous action" in AbuseFilter, so it is not throttled.

  • iff applied to Global Filters (so stewards etc. can manage this/it can target multiple projects), large projects will be opted out.

I don't understand this, what do you mean by "large projects will be opted out"? Who will opt them out, of what?

nb. no longer a steward, but just some hopefully helpful thoughts:

  • won't filters which hit an excessive number of edits be throttled? I think one which matches every IP edit is likely to hit this — admittedly, filter editors should try to make the filter more specific but this isn't always possible.

The implementation does not define the showcaptcha consequence as a "dangerous action" in AbuseFilter, so it is not throttled.

Good.

  • iff applied to Global Filters (so stewards etc. can manage this/it can target multiple projects), large projects will be opted out.

I don't understand this, what do you mean by "large projects will be opted out"? Who will opt them out, of what?

https://meta.wikimedia.org/wiki/Global_AbuseFilter#Opted_out_projects

  • iff applied to Global Filters (so stewards etc. can manage this/it can target multiple projects), large projects will be opted out.

I don't understand this, what do you mean by "large projects will be opted out"? Who will opt them out, of what?

https://meta.wikimedia.org/wiki/Global_AbuseFilter#Opted_out_projects

I see, thanks. The example patch in the task description is enabling CAPTCHA for just one wiki. Are there circumstances where we want to set $wmgEmergencyCaptcha across all projects without involving SREs? If not, then the AbuseFilter + showcaptcha consequence seems like it would suffice for the use case described in this task.

I see, thanks. The example patch in the task description is enabling CAPTCHA for just one wiki. Are there circumstances where we want to set $wmgEmergencyCaptcha across all projects without involving SREs? If not, then the AbuseFilter + showcaptcha consequence seems like it would suffice for the use case described in this task.

We've certainly seen attackers target multiple projects, so this might be a desired feature during certain incidents.

I see, thanks. The example patch in the task description is enabling CAPTCHA for just one wiki. Are there circumstances where we want to set $wmgEmergencyCaptcha across all projects without involving SREs? If not, then the AbuseFilter + showcaptcha consequence seems like it would suffice for the use case described in this task.

We've certainly seen attackers target multiple projects, so this might be a desired feature during certain incidents.

Ok. But then it sounds like the mechanism would be:

  • Enable a global abuse filter for showing a CAPTCHA on all projects
  • Create two local abuse filters on enwiki and jawiki

Which doesn't sound that bad. Just trying to avoid the need to build new software for this, if it can be easily solved with something we've already got.

  • Enable a global abuse filter for showing a CAPTCHA on all projects
  • Create two local abuse filters on enwiki and jawiki

Which doesn't sound that bad. Just trying to avoid the need to build new software for this, if it can be easily solved with something we've already got.

Yes, if we're fairly confident the opt-out isn't likely to expand to many more projects any time soon, I would agree.

  • Enable a global abuse filter for showing a CAPTCHA on all projects
  • Create two local abuse filters on enwiki and jawiki

If this is all something that any or even most stewards can do, LGTM for addressing this task. Let's also make sure the stewards know & have documented it for themselves?

Just trying to avoid the need to build new software for this, if it can be easily solved with something we've already got.

You could introduce superglobal filters which cannot be opted out of... *ducks for cover*

I see, thanks. The example patch in the task description is enabling CAPTCHA for just one wiki. Are there circumstances where we want to set $wmgEmergencyCaptcha across all projects without involving SREs? If not, then the AbuseFilter + showcaptcha consequence seems like it would suffice for the use case described in this task.

We've certainly seen attackers target multiple projects, so this might be a desired feature during certain incidents.

Ok. But then it sounds like the mechanism would be:

  • Enable a global abuse filter for showing a CAPTCHA on all projects
  • Create two local abuse filters on enwiki and jawiki

Which doesn't sound that bad. Just trying to avoid the need to build new software for this, if it can be easily solved with something we've already got.

What Japanese Wikipedia concern is global filter can not be disabled locally by local admins, so when T45761: Allow local disabling of global AbuseFilters is resolved we should ask Japanese Wikipedia to reconsider the opt-out.

In T45761#8849784 I further proposed that wiki can opt-in (i.e. enable) individual global filters, even if the wiki choose not to opt in global filter by default, (or the global filter is disabled in Meta, though this is irrelevant to this task). So instead of creating two local abuse filters, we can let enwiki opt in this specific filter, once we have such feature.

Are there circumstances where we want to set $wmgEmergencyCaptcha across all projects without involving SREs? If not, then the AbuseFilter + showcaptcha consequence seems like it would suffice for the use case described in this task.

This was discussed in today's WMF-Steward call.

An outstanding issue with AbuseFilter that $wmgEmergencyCaptcha was recently enabled for was to prevent filter maintainers from being spammed with notifications that the filter was matching a large volume of edits. Rate limiting those notifications (maybe max 1/filter/hour?) or being able to disable them would allow us to decline this task.

Rate limiting those notifications (maybe max 1/filter/hour?) or being able to disable them would allow us to decline this task.

There should be only one such notification per filter version. The notification is not resent for already throttled filters.
The timeline would be as follows: a steward (re)enables the filter, the filter starts matching actions globally, a threshold is exceeded, the notification is sent, a steward disables the filter. Then the loop starts over.

The timeline would be as follows: a steward (re)enables the filter, the filter starts matching actions globally, a threshold is exceeded, the notification is sent, a steward disables the filter. Then the loop starts over.

I might be very wrong, but wouldn't the same happen if a steward simply edits that filter, since that resets throttling? In that case, a checkbox that'd trigger silent throttling might still be helpful.

Yes, every change to a filter in fact resets its throttled status.

But let me make one thing more clear. Now, only "local filters" are actually throttled. A global filter is considered "local" only for metawiki. Not sure if this is a bug or feature, anyway this is how it works right now.