Sans frais de transaction, comment résister aux attaques

Rien n’indique que le nœud calculant possède ou non une transaction ayant une source plus ancienne. Je ne peux donc pas refuser son bloc parce qu’il a mis une transaction avec une source plus récente qu’une transaction que j’ai dans ma piscine.

De manière générale, on ne peux pas définir d’ordres ou de filtres parmi les transactions en piscine, car elle n’est pas consensuelle (c’est le but de la blockchain).

Une idée que j’avais proposé dans la review de ma RFC2 était de séparer les transactions en différentes catégories selon leur poids, et autoriser un certain nombre (variable au cour du temps pour s’adapter à la demande). Ça c’est bon. J’avais par contre proposé de pouvoir mettre plus de transaction d’une certaine tranche si les autres ne sont pas pleine. Mais ça, personne ne peux le vérifier, car on ne connait pas le contenu des piscines des autres. Pas moyen donc de savoir s’il n’a pas rempli la tranche parce qu’il n’avait plus de transactions ou parce qu’il veut faire d’autres transactions.

Je pense qu’une limite par catégorie de tailles peu être intéressante, après il faut voir si elle règle les problèmes et si on peux la contourner.

1 « J'aime »

Cette règle n’est pas une règle de blockchain, c’est juste un comportement des noeuds : ils écrivent dans la chaîne les transactions utlisant les sources les plus anciennes qu’ils ont en piscine, dans la limite de la taille du bloc.

L’idée est intéressante oui !

Mais si tu peux, c’est simplement que tu ne pourras pas empêcher d’autres nœuds de ne pas respecter cette règle. Et si la majorité des nœuds applique cette règle, alors le spam sera de fait endigué la majeure partie du temps (pour ce qui concerne cette règle de priorisation).

En tout cas je réfléchissais justement au spam des transactions ce midi (coïncidence !). Je me disais qu’il y a au moins une chose qu’on peut limiter immédiatement : l’enchaînement de plus de X transactions dans un même bloc. Par exemple si on limitait à 5 le nombre de transactions chaînées dans un bloc, alors un spammeur possédant N comptes qui s’amuse à envoyer X unités à son compte C1, qui envoie vers C2, qui envoie vers C3 … serait limité à 5 transferts par bloc pour ce montant.

On pourrait me rétorquer “oui mais l’attaquant peut aussi paralléliser les transferts, afin de réaliser N attaques simultanées”. C’est vrai. Mais aujourd’hui il peut déjà le faire avec 1 seul compte et spammer un seul bloc.

2 « J'aime »

En vérité, plus que d’essayer de définir des limites (qui seront de toute façon contournable du fait du nombre infini d’adresses possibles), je pense qu’il vaut mieux définir des priorités.

L’age des sources de transaction étant variable possible de la fonction “priorité”, mais ce n’est pas la seule que l’on peut imaginer.

Non car le nombre d’unités de monnaie n’est pas infini, lui. A tout instant il existe un maximum d’unités qui peuvent être envoyées, qui correspond au nombre total d’unités dans le système.

Et aussi, la limite dont j’ai parlé plus haut tu peux tout à fait sentir qu’elle est absolument nécessaire dès maintenant. C’est une faille béante qu’on a là.

En tout cas l’âge des sources est une variable particulièrement légitime, car plus une source est ancienne, moins l’utilisateur sollicite le système et donc plus il le préserve/l’économise.

Maintenant pour éviter la parallélisation de l’attaque, la solution évidente qui me vient est d’avoir également un poids fonction du montant de la transaction par rapport aux autres montants concurrents.

Et donc au final, d’avoir une priorité fonction de ces 2 éléments.

1 « J'aime »

Du coup oui c’est sur chaque membre peu appliquer cette règle, mais elle ne fait donc pas partie du protocole. C’est déjà une bonne piste.

Une idée est de suivre le graphe des sources et de prendre en compte l’âge des transactions sur plusieurs pas. Une transaction après 5 mins apres 5 mins serait moins prioritaire qu’une après 1 semaine après 1 semaine.

Je ne savais pas que l’on pouvait effectuer des transactions chaînées dans un seul bloc. Il n’y a pas forcément besoin de les interdire, mais avec la règle au dessus ils seront très handicapés et ne passeront que s’il n’y a pas d’autres en attente.

J’ai créé le ticket#1242 avec priorité#0 (cc @elois) à cet effet car oui, cette faille devient particulièrement urgente avec le nombre de membres qui augmente constamment. Tôt ou tard les ennemis vont se montrer, mieux vaudra avoir colmaté ce genre de faille avant leur arrivée.


Si, c’est nécessaire de les interdire passé une certaine longueur (par exemple 5), sinon un spammeur peut faire artificiellement grossir la blockchain jusqu’au buffer overflow et détruire la monnaie. En effet il peut, à l’aide de 2 comptes qu’il possède, chaîner des transactions ping-pong et les soumettre au réseau. Au premier bloc il peut atteindre la taille max du bloc, et s’il continue la blockchain va augmenter la taille des blocs de 10%, puis 10%, puis 10%, … c’est juste une énorme erreur de ma part de ne pas avoir codé cette règle plus tôt. Il faut cette limite, rapidement.

Encore une autre suggestion : prioriser les transactions qui réduisent le nombre de sources.

4 « J'aime »

La limite de bloc pourrait monter de façon logarithmique.

Sinon il faudrait mettre une limite en effet. Dans quel cas on a besoin de publier une suite de transactions dans un même bloc ? Je vois une utilité dans le cadre des smart contracts, mais pas avec de simples transactions à première vue.

Quand tu fais du change par exemple : besoin de rassembler des sources avant dépense car trop nombreuses. Ça arrive très régulièrement déjà dans la Ğ1.

D’accord je vois. 5 me semble largement suffisant du coup :slight_smile:

Oui et l’augmentation logarithmique me parait bien aussi.

Bonjour @regisg

concernant le spam j’y ai mis mon grain de sel :slight_smile:


sinon pour la consommation des sources,
il est envisageable de se mettre d’accord coté application client pour qu’une transaction consomme l’ensemble des sources verrouillées par simple signature. *

ce qui peut d’une certaine manière eviter le spam dans le sens où il faut attendre que duniter traite et valide en blockchain la transaction et rend "indisponible " pendant ce laps de temps l’accès a ces sources pour de future transaction.

le point positif c’est que ca réduit les sources a une seule pour une future transaction simple signature.
le point négatif c’est que l’on soit contraint d’attendre la validation de la blockchain pour en effectuer une autre qui soit acceptée…

nb: a defaut de le faire sur l’ensemble des sources et pour pallier a ce dernier point,
peut etre faire cette selection <=>nombre de sources a consommées, en proportion du nombre de sources disponibles (toujours dans le cas simple signature) sachant qu’un utilisateur qui n’effectue aucune transaction sur 1 mois va disposer à minima + ou - de 30 sources (1DU par jour)

Quelle différence entre faire plein de petites transactions vers des petits comptes ?

L’attaque sera dans ce cas limitée au nombre de Ğ1 possédées, à raison de 1 Ğ1 par compte. Tandis que dans mon exemple il n’y a aucune limite.

Ceci dit, c’est un fonctionnement “normal”, légitime, tout utilisateur a le droit de répartir ses Ğ1 et les faire circuler. Cela peut s’assimiler à une utilisation plus intensive de la blockchain. Tant que cela n’empêche pas les autres utilisateurs de faire leurs virements, il n’y a aucun problème en fait (à part pour ceux qui stockent la blockchain).

@cgeek ok je veut bien implémenter ça dans la 1.6 mais quelqu’un peut t’il résumé les règles a mettre en place ?

Juste pour éviter toute ambiguïté : je t’ai mis en copie pour que tu suives le problème, car il me semble important. Tu peux le faire si tu veux, mais on en est encore au stade de la réflexion pour l’instant, avec propositions/réfutations.

Il faudra ensuite spécifier cela techniquement dans le document de protocole.

1 « J'aime »

merci c’est bien ce qu’il me semblais a la lecture il n’y a pas encore de conclusion précise sur les règles a coder !

Ok alors je résume les idées intéressantes qui se sont dégagés :

  1. Limiter les transactions chainés à une profondeur maximale de 5
  2. Prioriser les transactions qui réduisent le nombre de sources.
  3. Prioriser les transactions a plus gros montant
  4. Fixer des quotas par tranches de montants

Voici donc une proposition de spec :

Créer des quotas par tranche ET par issuer :
Tranche 1 : montant total inférieur à 3 DU courant : maximum 1 transaction par bloc et par issuer
Tranche 2 : montant total inférieur à 10 DU courant : maximum 2 transactions par bloc et par issuer
Tranche 3 : montant total entre 10 et 100 DU courant : maximum 3 transactions par bloc et par issuer
Tranche 4 : montant total supérieur a 100 Du courant : maximum 5 transactions par bloc et par issuer

Lorsqu’une transaction contient plusieurs issuers le compteur de chaque issuer est incrémenté, s’il existe un seul issuer pour lequel le compteur dépasse le quota alors le bloc est invalide.

Chaque transaction compte pour 1, qu’elle soit chainée ou pas. Notez la cohérence avec la profondeur max pour les transactions a gros montant !

Enfin , un attaquant qui tenterai plein de micro-transactions en parallèle serait limité a 1 transaction par clé (sauf a dépasser les 3 DU courant mais ça commence a faire des fonds…).

Point important : pour éviter qu’un spammer ne squate les blocs pour empecher les autres d’échanger, je ne propose aucun limite sur le nombre d’issuers ni sur le nombre de transactions totales, la règle de la taille limite des blocs me semble déjà bien.

Une dernière chose : je serais favorable a ce que l’on limite le nombre max d’input d’une transaction à 64, dans les faits les clients respectent déjà cette règle et chaine au delà de 40 inputs. Idem pour le nombre max d’output, afin d’empêcher une attaque par transactions prenant trop de place dans le blocs.

a noté que ces propositions concernent exclusivement les règles blockchain, et ne remplacent pas le besoin de fixer des quotas par piscine déjà prévu ici : https://git.duniter.org/nodes/typescript/duniter/issues/1152

3 « J'aime »

Quand je parlais de tranches, ce n’était pas par rapport aux montants mais à la taille en octet des transactions. Il n’y a pas de problème de scaling entre une transaction de 1 G1 et une de 10 kG1. Il y en a par contre une entre une transaction de 100 octets et une de 20000. C’est là qu’il doit y avoir un limite, et un système de tranches (ou encore mieux une notion de quota selon une fonction continue de la taille) me semble nécessaire.

EDIT : Après relecture en effet il est plus simple de spammer avec 1 G1 que 10k :stuck_out_tongue: Par contre il faut aussi penser au payload de la transaction, qui ne contient pas uniquement la somme d’argent mais aussi les conditions de dépenses, qui pourraient augmenter de taille avec le RFC2. C’est dans ce cas là que des tranches en poids de transaction me semblent importantes.

Les spec que je propose s’appliquent au protocole actuel. De plus, quelque soit les conditions d’output il y a toujours un montant total d’inputs nécessairement connu et certain au moment de l’écriture de la transaction, alors la seule faille qu’il restera dans le protocole binarisé c’est la possibilité d’un output au script trop gros, dans ce cas le plus simple me semble être d’imposer une taille binaire maximale pour chaque output OU par transaction.