Aventuras con la abstracción de cuentas – Riesgos y mitigaciones en __validate__.
Starknet está a la vanguardia de la abstracción de cuentas, habiéndola incorporado directamente al protocolo.
Una de las grandes ventajas de la abstracción de cuentas es la capacidad de proporcionar una lógica de validación personalizada en la cuenta de un usuario, como la validación biométrica de las transacciones y los límites de retirada diarios.
La forma en que funciona es que cuando una transacción se envía a la red, se valida con el punto de entrada __validate__ del contrato de la cuenta del remitente, donde, entre otras cosas, se valida la firma.
Una vez que la validación ha pasado con éxito, el punto de entrada __execute__ es llamado y ejecuta la transacción real.
Riesgos con __validate__.
Lo ideal sería implementar lógica de validación arbitraria como parte del código __validate__, pero esto abre potenciales vectores de ataque DOS.
Dado que las transacciones que no superan la validación son RECHAZADAS antes de su ejecución, no incurren en ningún gasto. Esto significa que un atacante puede desplegar una implementación __validate__ muy costosa que gaste muchos recursos y luego simplemente falle – incurriendo en un alto coste computacional sin ninguna tasa asociada.
Mitigación de riesgos
Starknet toma varias contramedidas para mitigar el vector DOS anterior.
Cálculo de límites
La medida más directa e intuitiva es limitar el cómputo en __validate__. En concreto, para limitar el número de pasos que puede ejecutar la validación de la transacción.
Una vez alcanzado ese límite, la validación falla. Esta limitación limita la cantidad potencial de cálculos que se pueden realizar sin pagar una tasa.
RECHAZAR transacciones en la pasarela
Otra contramedida es ni siquiera incluir las transacciones que no pasen __validate__ en la cola del secuenciador. De hecho, este cambio está implementado en la versión 0.12.1 de Starknet.
Cuando se envíe una transacción, se llamará al punto de entrada __validate__ del contrato de la cuenta emisora en la pasarela. Si la validación falla, la transacción será rechazada inmediatamente sin más trámite.
Esto es beneficioso porque, una vez que una transacción pasa la comprobación de validación de la pasarela, será procesada por el secuenciador, cuya capacidad de cálculo es un recurso mucho más escaso que la capacidad de cálculo de la pasarela.
Pero espere: ¿cómo puede la pasarela estar segura de que la transacción no es realmente válida? ¿Y si la validación de la transacción depende de algún estado externo?
Evite llamar_contrato
Otra limitación menos trivial es bloquear las llamadas al sistema call_contract desde __validate__.
Ahora te preguntarás: ¿por qué necesitamos esta limitación una vez que el cómputo está limitado y las transacciones no válidas son rechazadas en la pasarela?
Para explicar esta limitación, tenemos que suponer que:
- La llamada al sistema call_contract está permitida en __validate__.
- MEV es posible en Starknet (en el momento de escribir estas líneas, todavía no es el caso en la versión 0.12.1 de Starknet, ya que las transacciones se procesan secuencialmente).
- Rechazar transacciones es mucho más barato en la pasarela que en el secuenciador.
Dadas estas suposiciones, considere el siguiente ataque:
- Un atacante despliega N contratos de cuenta, todos los cuales implementan una función __validate__ que está justo en el límite del cómputo permitido.
- Hacia el final de la lógica __validate__ maliciosa, el atacante consulta algún estado en algún otro contrato, utilizando call_contract. Esto hace que __validate__ tenga éxito o falle según la respuesta true / false respectivamente.
- Ahora el atacante envía T transacciones de cada uno de los N contratos de cuenta maliciosos, lo que significa NxT transacciones en total. Todos ellos pasan la pasarela, ya que el atacante se aseguró en el momento del envío de la transacción de que el call_contract devolvería true.
- Justo después, el atacante envía una transacción que cambia la respuesta call_contract a false, intentando utilizar MEV para que esta transacción se ejecute antes que las transacciones NxT de los Contratos de Cuenta maliciosos.
- Si el atacante tiene éxito, y son capaces de cambiar el estado de verdadero a falso antes de las transacciones NxT, entonces con una sola transacción el atacante será capaz de crear transacciones NxT RECHAZADAS, utilizando el máximo cómputo, sin pagar ninguna tasa ya que las transacciones fallan __validate__ durante la ejecución. REJECT se producirá en el secuenciador, que, como se ha dicho, es un recurso más limitado y escaso en la red.
Así, por RECHAZARde las transacciones a nivel de pasarela, así como evitar la dependencia de __validate__ en un estado externo a través del contrato_convocatoriamitigamos el riesgo de que un atacante pueda poner en cola muchas transacciones que pasen por la pasarela y RECHAZAR en la secuenciación, incurriendo en una gran sobrecarga en la red sin devengar tasa alguna.
En la próxima entrega de esta serie le mostraremos cómo implementar el flujo de validación de última generación de la cuenta multipropietario, otra posibilidad clave de la abstracción de cuentas, teniendo en cuenta estas limitaciones. Acompáñenos en nuestra próxima aventura de AA.
Yoav Gaziel es cofundador de Braavos, el primer monedero diseñado específicamente para Starknet, y anteriormente trabajó 10 años como director de tecnología en dos destacadas empresas emergentes israelíes.
Si desea obtener más información sobre la abstracción de cuentas, visite nuestra guía especial aquí. Y si quieres profundizar en nuestro código, visita nuestro perfil de GitHub.