CAPTCHA
Las páginas de cuenta de un portal aceptan envíos de cualquiera: un script puede crear cuentas o hacer que el correo del portal restablezca enlaces de contraseña y confirmación a las direcciones que elija. Un CAPTCHA pide a cada visitante que demuestre que es una persona antes de enviar el formulario. Power Portals Pro soporta Cloudflare Turnstile, Google reCAPTCHA (v2 y v3) y hCaptcha, y está desactivado hasta que configures uno.
Nota
El servidor revisa el desafío, no solo la página. Una vez configurado un proveedor, los endpoints de autenticación y las páginas de cuenta renderizadas por el servidor rechazan la presentación de un formulario protegido sin un desafío resuelto, sea cual sea el envío del navegador.
Qué formas están protegidas
CaptchaOptions.Forms elige los formularios, como una combinación de CaptchaForms valores. El predeterminado protege los formularios que un llamador automático puede abusar sin conocer ninguna contraseña.
| CaptchaForms | Forma | Por defecto |
|---|---|---|
Register |
Crear una cuenta local. | On |
ForgotPassword |
Pidiendo un enlace para restablecer la contraseña. | On |
ResendEmailConfirmation |
Pido otro enlace de confirmación por correo electrónico. | On |
Login |
Iniciar sesión con una dirección de correo electrónico y contraseña. Actívalo para ralentizar la adivinanza de contraseñas; las contraseñas incorrectas repetidas también bloquean la cuenta durante un tiempo. | Fuera |
ExternalLogin |
Completar un inicio de sesión a través de Microsoft, Google u otro proveedor con una dirección de correo electrónico que el proveedor no verificó, a la que el portal luego envía una confirmación por correo. Un inicio de sesión cuya dirección el proveedor haya verificado se completa sin desafío. | Fuera |
Elegir un proveedor
Los tres proveedores funcionan igual en lo que respecta al portal; difieren en lo que ve el visitante y en qué cuenta necesitas. Cada uno tiene un nivel gratuito.
| Proveedor | Cuenta que necesitas | Lo que ve el visitante | Enlaces |
|---|---|---|---|
| Torniquete Cloudflare | Una cuenta gratuita de Cloudflare. Tu portal no tiene que estar alojado en Cloudflare ni usar su DNS. | Normalmente no hay nada que hacer: la comprobación se ejecuta sola y solo de vez en cuando pide un clic. | Panel · Documentación |
| Busca en Google reCAPTCHA v2 | Una cuenta de Google. | La casilla de "No soy un robot", a veces seguida de un puzzle de imágenes. | Consola de administración · Documentación |
| hCaptcha | Una cuenta hCaptcha gratuita. | Una casilla de verificación, a veces seguida de un puzzle de imágenes. | Panel · Documentación |
| Busca en Google reCAPTCHA v3 | Una cuenta de Google. | Nada en absoluto: Google califica cada envío y la insignia de Google queda en la esquina de la página. Un visitante que obtiene una puntuación demasiado baja es rechazado y no puede demostrar lo contrario. | Consola de administración · Documentación |
Elijas lo que elijas, el proveedor te da dos claves para tu sitio: una clave del sitio, que es pública y se envía a todos los navegadores para dibujar el widget, y una clave secreta, que solo el servidor usa para comprobar la respuesta de un visitante. Mantén la clave secreta fuera del control de versiones.
Montaje del torniquete Cloudflare
- Regístrate para una cuenta gratuita en dash.cloudflare.com. No necesitas añadir una web ni mover ningún DNS.
- Abre el torniquete desde el menú del panel de control y elige Añadir widget.
- Nombra el widget y añade todos los nombres de host desde los que se sirve el portal: su dominio de producción, cualquier ranura de despliegue y
localhost, si pruebas con claves reales. - Elige el modo Widget gestionado , que solo pide un clic cuando Cloudflare no está seguro.
- Crea el widget y copia su clave del sitio y clave secreta.
Configurando Google reCAPTCHA v2
- Inicia sesión en la consola de administración de reCAPTCHA con una cuenta de Google y crea un sitio nuevo.
- Elige Desafío (v2) y luego casilla de verificación "No soy un robot".
- Añade todos los dominios desde los que se sirve el portal, y
localhostsi pruebas con claves reales. - Deja activado Verificar el origen de las soluciones reCAPTCHA , para que se rechace un token resuelto en otro sitio. Envía y copia la clave del sitio y la clave secreta.
Importante
Usa proveedor
ReCaptchaV2y laCaptcha:ReCaptchaV2sección solo para una casilla de verificación v2 "No soy un robot" — el widget muestra "Tipo de clave inválida" para cualquier otra. Una clave v3 va bajoReCaptchaV3, abajo; la insignia invisible v2 no es compatible. Google puede pedirte que adjuntes la clave a un proyecto Google Cloud; eso no cambia cómo la usa el portal.
Configurando Google reCAPTCHA v3
la versión 3 no muestra ningún desafío. La página pide a Google un token cuando se envía el formulario, etiquetado con el formulario del que proviene, y el servidor rechaza un token puntuado abajo MinimumScore o etiquetado para otro formulario. Usa el proveedor ReCaptchaV3 y su propia sección: Captcha:ReCaptchaV3una clave v3 es una clave diferente a una v2.
- En la consola de administración de reCAPTCHA, crea un nuevo sitio y elige Basado en puntuaciones (v3).
- Añade todos los dominios desde los que se sirve el portal, y
localhostsi pruebas con claves reales. Deja activado Verificar el origen de las soluciones reCAPTCHA . - Envía y copia la clave del sitio y la clave secreta en
Captcha:ReCaptchaV3. - Establece
MinimumScore, de 0.0 a 1.0. Por defecto se pone en 0.5, el punto de partida sugerido por Google; la consola de administración muestra las puntuaciones que obtienen tus visitantes para ajustarlo.
Importante
Un visitante puntuado abajo
MinimumScorees rechazado sin nada que resolver, y se le dice que lo intente de nuevo en un momento. Sube con cuidado y observa las puntuaciones en la consola de administración después de hacerlo. Google no publica claves de prueba para la v3.
Configuración de hCaptcha
- Regístrate para una cuenta gratuita en dashboard.hcaptcha.com.
- En Sitios, añade un sitio nuevo y copia su clave del sitio.
- En la configuración del sitio, añade todos los nombres de host desde los que se sirve el portal. hCaptcha no acepta
localhostni127.0.0.1: para probar claves reales en tu máquina, asigna un nombre comodev.example.coma127.0.0.1en el archivo de tu host y añade eso, o usa las claves de prueba que aparecen a continuación. - Copia la clave secreta desde la configuración de tu cuenta (o la secreta propia del sitio, donde el panel de control la ofrece).
Claves de prueba para el desarrollo local
Cada proveedor publica un par de claves de prueba que funcionan con cualquier nombre de host, localhost incluido, y siempre pasan — para que puedas probar los formularios del portal antes de crear una cuenta. El widget muestra que está en modo prueba.
| Proveedor | Clave del sitio | Llave secreta |
|---|---|---|
Turnstile |
1x00000000000000000000AA |
1x0000000000000000000000000000000AA |
ReCaptchaV2 |
6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI |
6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe |
HCaptcha |
10000000-ffff-ffff-ffff-000000000001 |
0x0000000000000000000000000000000000000000 |
Importante
Las claves de prueba aceptan a todos los visitantes, incluidos los robots. Nunca las despliegues: reemplázalas por tus propias llaves antes de que el portal esté en funcionamiento.
Configuración del portal
Los proyectos generados a partir de las plantillas se vinculan CaptchaOptions desde la Captcha sección de appsettings.json, que comienza por Provider set a None. Cada proveedor tiene una sección propia para sus claves — Turnstile, ReCaptchaV2, ReCaptchaV3 y HCaptcha — y Provider elige cuál se usa, así que puedes mantener varias configuradas y cambiar entre ellas con una sola configuración. Coloca la clave del sitio de cada proveedor en su sección. Forms Toma los nombres de los formularios separados por comas; déjalo fuera para mantener el valor predeterminado.
{
"Captcha": {
"Provider": "Turnstile",
"Forms": "Register, ForgotPassword, ResendEmailConfirmation",
"Turnstile": {
"SiteKey": "<Turnstile site key>"
},
"ReCaptchaV2": {
"SiteKey": "<reCAPTCHA v2 site key>"
},
"ReCaptchaV3": {
"SiteKey": "<reCAPTCHA v3 site key>",
"MinimumScore": 0.5
}
}
}
Guarda las claves secretas en los secretos de usuario durante el desarrollo, y en Key Vault o en la configuración del App Service cuando se despliegan — nunca en appsettings.json. En Key Vault, nómbralas Captcha--Turnstile--SecretKey y así sucesivamente:
dotnet user-secrets set "Captcha:Turnstile:SecretKey" "<Turnstile secret key>"
dotnet user-secrets set "Captcha:ReCaptchaV2:SecretKey" "<reCAPTCHA v2 secret key>"
dotnet user-secrets set "Captcha:ReCaptchaV3:SecretKey" "<reCAPTCHA v3 secret key>"
dotnet user-secrets set "Captcha:HCaptcha:SecretKey" "<hCaptcha secret key>"
Esta es la línea Program.cs que lee la sección. Un portal que no se generó a partir de una plantilla lo añade después AddPowerPortalsProWebServer()de :
builder.Services.Configure<CaptchaOptions>(builder.Configuration.GetSection("Captcha"));
O establecer las opciones en código, como cualquier otra IOptions clase:
builder.Services.Configure<CaptchaOptions>(options =>
{
options.Provider = CaptchaProvider.HCaptcha;
options.HCaptcha.SiteKey = "<site key>";
options.HCaptcha.SecretKey = builder.Configuration.GetRequiredValue("Captcha:HCaptcha:SecretKey");
options.Forms = CaptchaForms.Register | CaptchaForms.ForgotPassword | CaptchaForms.Login;
});
Propina
Un proveedor configurado sin ambas claves detiene el portal al inicio con un mensaje que indica lo que falta, en lugar de empezar con formularios que rechazarían a todos los visitantes.
Añadir el reto a tus propios formularios
Las páginas de cuenta de la plantilla ya lo incluyen. En un formulario propio, coloca el Captcha componente — no se generará nada a menos que el formulario que nombres requiera un desafío — y envía el token que entrega cuando se envía el formulario: TakeTokenAsync() en Blazor, takeToken() en el ref en React. Una presentación que el servidor rechazó para el desafío surge CaptchaVerificationException en Blazor y CaptchaVerificationError en React.
const captcha = useRef<CaptchaHandle>(null);
const register = async () => {
try {
await auth.registerAsync({ email, password, captchaToken: (await captcha.current?.takeToken()) ?? null });
} catch (error) {
// Le dice al visitante que resuelva el desafío de nuevo y lo reinicia.
if (error instanceof CaptchaVerificationError) captcha.current?.reportNotSolved();
}
};
<Captcha ref={captcha} form={CaptchaForms.Register} /><Captcha @ref="_captcha" Form="CaptchaForms.Register" />
@code {
private Captcha? _captcha;
private async Task RegisterAsync()
{
try
{
await AuthService.RegisterAsync(new RegisterRequest
{
Email = _email,
Password = _password,
CaptchaToken = await _captcha!.TakeTokenAsync(),
});
}
catch (CaptchaVerificationException)
{
// Le dice al visitante que resuelva el desafío de nuevo y lo reinicia.
await _captcha!.ReportNotSolvedAsync();
}
}
}Un token es válido para una sola entrega, así que cogerlo también reinicia el desafío: sea cual sea el resultado — una contraseña incorrecta, una dirección ya en uso — el siguiente intento recibe una nueva sin que la página haga nada. En reCAPTCHA v3 no hay token hasta que se tome, así que no mantengas pulsado un botón de enviar hasta que TokenChanged (Blazor) o onTokenChange (React) reporten uno.
Una página de Blazor renderizada por el servidor que se llama UserManager a sí misma, en lugar de pasar por IAuthService, comprueba el token antes ICaptchaVerifier de actuar:
@inject ICaptchaVerifier CaptchaVerifier
if (!await CaptchaVerifier.VerifyAsync(CaptchaForms.Register, await _captcha!.TakeTokenAsync()))
{
await _captcha!.ReportNotSolvedAsync();
return;
}
Intentos de limitación por dirección
Independientemente de si se configura o no un CAPTCHA, el portal limita la frecuencia con la que una dirección envía cada formulario que cualquiera puede enviar sin iniciar sesión — iniciar sesión, registrarse, restablecer una contraseña, reenviar una confirmación, aceptar una invitación. Por defecto, una dirección puede enviar cada una 20 veces por minuto; a partir de entonces, se responde con 429 Too Many Requests hasta que pase el minuto. Cada formulario se cuenta por separado. Cambiar el límite bajo PowerPortalsPro:SignInRateLimit; a PermitLimit de 0 lo apaga.
{
"PowerPortalsPro": {
"SignInRateLimit": {
"PermitLimit": 20,
"Window": "00:01:00"
}
}
}
Importante
El límite cuenta la dirección desde la que proviene una solicitud. Detrás de un proxy o gateway que no transmite la dirección del visitante — Azure Front Door, Application Gateway, un balanceador de carga propio — cada visitante llega desde los proxys, y comparten un solo recuento. Reenvía la dirección del visitante con
UseForwardedHeaders, nombrando el proxy enKnownProxiesoKnownNetworks.
Política de Seguridad de Contenidos
El widget se carga desde la web del proveedor. Si tu portal envía una Content-Security-Policy cabecera, permite que los hosts del proveedor entren script-src y frame-src (hCaptcha también necesita style-src y connect-src):
| Proveedor | Presentadores |
|---|---|
Turnstile |
https://challenges.cloudflare.com |
ReCaptchaV2 |
https://www.google.com/recaptcha/, https://www.gstatic.com/recaptcha/ |
HCaptcha |
https://hcaptcha.com, https://*.hcaptcha.com |
Resolución de problemas
- Cada envío es rechazado. La clave secreta es incorrecta o pertenece a otra clave de sitio. El servidor registra un error nombrando la queja del proveedor cada vez.
- El formulario dice que el desafío no pudo cargarse. El script del proveedor fue bloqueado — por una extensión del navegador, un filtro de red o una Política de Seguridad de Contenidos — o el navegador está fuera de línea.
- El widget muestra un error sobre el dominio. El nombre de host desde el que se sirve el portal no está en la lista del proveedor para esta clave del sitio.
- Se rechaza un desafío resuelto. Los tokens caducan tras unos minutos y pueden usarse una vez. El widget normalmente se renueva solo; si un visitante deja el formulario abierto, lo resuelve de nuevo.
- El portal no se inicia después de configurar un proveedor. El de
SiteKeyese proveedor oSecretKeyfalta — bajoCaptcha:Turnstile,Captcha:ReCaptchaV2,Captcha:ReCaptchaV3oCaptcha:HCaptcha— o, para reCAPTCHA v3,MinimumScoreno está entre 0 y 1. El error de arranque indica qué opciones fallaron.
