8768 sujets

Développement web côté serveur, CMS

Bonjour,
malgré mes précautions (obligation de remplir les champs), je reçois sur mes formulaires des messages complètement vides. Ni adresse mail ni texte. Ou parfois des trucs du genre xzqa.
Je sais que les précautions en html ne protègent de rien, mais j'ai des protections anti-spam en php. Peut-être ne servent-elles à rien pour ce genre d'envoi vide. Je suis étonné surtout de l'intention. Je n'ai eu pour le moment aucune attaque ou intrusion, ni même du SPAM. Des personnes s'amusent-elles ? C'est toujours un peu angoissant.
Au milieu des autres messages pertinents, ces tentatives sont peu nombreuses, du genre une ou deux par semaine, en moyenne sur un mois.
Ma question, est-ce qu'il y a un script php pour éviter ça ?
Modérateur
Salut Bongota,

Si c'est ton site et le form contact ?


<?php
    if(!empty($_POST)){
        $clean_methods = [
            'trim',
            'strip_tags',
            'htmlspecialchars',
        ];
        foreach($clean_methods as $method){
            $_POST = array_map($method, $_POST);
        }
        foreach($_POST as $k => $v){
            switch($k){
                case 'mailpost':
                case 'message':
                    if(empty($v)){
                        $_POST['error'][$k] = "le champ ne peut être vide";
                    }
                    break;
            }
        }
    }


Je te laisse faire la suite
Merci,
je ne connaissais pas cette fonction, mais en lisant les docs qui vont avec, je vois que mon problème ne sera pas résolu. En effet, empty met une alerte si le formulaire est vide, mais rien n'empêche l'expédiant de le remplir avec n'importe quoi (soit un mail valide mais faux, soit un texte farfelu ou composé d'une suite de lettres aléatoires, comme ceux que je reçois).
J'en demande sûrement trop, je ne crois pas qu'il y ait une solution.
C'est pourtant angoissant de recevoir, comme cette nuit, ça : xqzapq, et c'est tout, sans adresse mail, pourtant en required en html. Une personne qui s'amuse ou qui tente quelque chose ?

@niuxe. Par contre, là, ton script peut être utile, parce que je reçois aussi des réponses sans aucun texte. Je vais voir ça.
Modifié par Bongota (28 May 2024 - 20:03)
Bonsoir,

La solution à laquelle tout le monde pense, c'est les CAPTCHA. Personnellement je suis contre, pour plusieurs raisons:
1 - C'est toujours source de frustration pour les utilisateurs, et c'est même parfois totalement bloquant car trop compliqué ou pas accessible
2 - Les bots s'améliorent sans cesse et arrivent de mieux en mieux à les passer, ce qui fait que ce n'est plus une solution aussi fiable qu'auparavant
3 - En conséquence du point 2, on te demande de faire des trucs de plus en plus frustrant/compliqués/inaccessibles
4 - En utilisant les systèmes proposés par les GAFAM, on contribue gratuitement à leur entraînement/renforcement

En réalité, on fait complètement fausse route avec les CAPTCHA. Il faut les bannir, bientôt ils seront complètement inutiles.

La première chose à vérifier, selon moi, c'est la provenance de l'envoi, i.e. l'adresse IP de l'expéditeur.
Avec les registres PBL, SBL, XBL, etc. on peut savoir si une IP provient probablement de chez un spameur, mais pas seulement. On a une assez bonne probabilité de faire la différence entre l'IP d'un particulier et celle d'un serveur.
Ca fait déjà un tri non négligeable de jeter directement tout ce qui vient d'un spameur ou visiblement pas de chez un particulier.

Toujours concernant l'adresse IP, jeter au-delà du nième message provenant de la même IP en moins d'un certain laps de temps. Par exemple, pas plus de 5 messages par heure par IP.
Même si les bots ajoutent de plus en plus souvent des patterns aléatoires espacés dans le temps pour ne pas se faire attraper, ça permet quand même d'éliminer un nombre pas si négligeable que ça de bots relativement stupides

La deuxième chose, c'est évidemment de vérifier l'adresse e-mail indiquée.
ON peut facilement vérifier si le domaine existe et s'il a bien un enregistrement MX. Comme ça adieu les aaaa@aaaa.aaa. Ca fait de nouveau un beau paquet de spam en moins.
C'est par contre impossible de savoir si aaaa@gmail.com existe sans réellement essayer d'envoyer un e-mail. Mais attention, il y a des domaines piège qui enregistrent instantanément ton adresse IP comme spameur si tu essayes de leur envoyer ne serait-ce qu'un seul e-mail, donc méfiance !

IL y a des services qui te proposent de vérifier la fiabilité d'une adresse e-mail, et en particulier si ce n'est pas un e-mail jetable ou domaine piège. Tu lui donne une adresse, il te donne un score. Le gros problème, c'est que ces services sont très cher (rapidement plusieurs centaines d'euros par mois selon le volume à valider).

Pour le contenu textuel des messages, il y a quelques classiques:
1 - La liste de mots-clés. ON jette le post au-delà de la troisième occurrence trouvée.
2 - Le nombre d'URL, ou alors, plus subtil, un rapport entre le nombre d'URL et le nombre de mots. Par exemple, on jette le post s'il y a plus de 5 URL, ou alors si plus de 20% du texte sont des URL. Mention spéciale au message qui commence par un URL et qui compte triple...
3 - Détecter ce qui a l'air d'être du code HTML, JavaScript, etc. et là pareil, si tu ne t'attends pas à en avoir, tu vires

A ce stade on a probablement viré 95% des bots inutiles, en tout cas ça a été le cas pour moi.
LE tout, sans CAPTCHA, sans truc à la con, c'est totalement transparent pour l'utilisateur normal.

Mais si ça continue, pour les messages aléatoires, il n'y a hélas pas 36 solutions, il faut faire de la statistique sur les mots.
- ON pourrait se fonder sur un dictionnaire et jeter un message qui a plus de x% de mots inconnus (il faut quand même être tolérant avec les fautes d'orthographe et du coup c'est difficile à ajuster).
- ON pourrait analyser les digrammes ou les trigrammes, et là aussi, éliminer les messages qui dépassent un seuil de combinaisons improbables... mais c'est pareil, pas évident le fine tuning.

Pour ma part, pour l'instant, je n'ai pas mis en place ce dernier volet. Je reçois quand même nettement moins de spam qu'avant toutes ces mesures.
Super, quel long document.
Je vais me coucher et je verrai ça demain.
Je sais déjà que pour le CAPTCHA, c'est non, j'ai déjà lu des docs et envisagé ceci. Mais j'ai abandonné. Je suis moi-même énervé par ces CAPTCHA.
Merci.
Modérateur
Bonsoir,

Confronté dernièrement à des robots qui spammé allégrement un formulaire avec un capcha tout simple (indiquer la lettre ou chiffre en x position) , j'ai pour le moment réduit à zéro ces attaques en passant le formulaire dans un template. Voir https://developer.mozilla.org/fr/docs/Web/HTML/Element/template et un test exemple sur un de mes pen https://codepen.io/gc-nomade/details/rNoXPLm



Est ce une simple coïncidence, en tout cas, je n'ai plus rien à modéré . C'est assez facile à mettre en place avec les explications et exemples données sur MDN .

Pour le rendre encore moins visible, tu peut aussi stocké ton template HTML dans une variable JS, l'inserer dans ton document, puis l’insérer dans la page pour le visiteur. Il devient plus difficile à trouver et à utiliser par un script/robot de cette manière.

J'ai un codepen exemple si cela peut t'aider à voir et tester l'astuce : https://codepen.io/gc-nomade/pen/PoXMVjM

il y aussi https://caniuse.com/?search=template pour te rassurer sur le support actuel.

Cela n’exclue pas la vérification de ce que tu reçoit, comme indiqué par les autres intervenants. En fait il ne faut jamais l'exclure ni faire confiance à ce que des formulaires peuvent t'envoyer Smiley cligne


Cdt
Modifié par gcyrillus (28 May 2024 - 22:44)
Modérateur
tout à l'heure, je n'étais pas dans mon env de dev

Regarde ça :

<?php
    if(!empty($_POST)){
        $clean_methods = [
            'trim',
            'strip_tags',
            'htmlspecialchars',
        ];
        foreach($clean_methods as $method){
            $_POST = array_map($method, $_POST);
        }

        if(!filter_var($_POST['mailpost'], FILTER_VALIDATE_EMAIL)){
            $_POST['error']['mailpost'] = "l'email saisie n'est pas valide";
        }
        if(empty($_POST['message'])){
            $_POST['error']['message'] = "le champ ne peut être vide";
        }

        if(!isset($_POST['error'])){
            echo "envoyer mail";
            exit();
        }
    }
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/foundation-sites@6.8.1/dist/css/foundation-float.min.css" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/foundation-sites@6.8.1/dist/css/foundation-prototype.min.css" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/foundation-sites@6.8.1/dist/css/foundation-rtl.min.css" crossorigin="anonymous">
    <style>
.grid-container{
    max-width: 600px;
}
input, textarea{
    margin-bottom: 0 !important;
}
.error{
    color: #f00;
}
    </style>
</head>
<body>
    <div class="grid-container margin-vertical-3">
        <form action="<?= htmlspecialchars($_SERVER['PHP_SELF']) ?>" method="post">
            <p>
                <label>
                    <span>email</span>
                    <input type="text" name="mailpost" value="<?= !empty($_POST['mailpost'])? $_POST['mailpost'] : ''?>">
                </label>
                <?php if(!empty($_POST['error']['mailpost'])): ?>
                <span class="error"><?= $_POST['error']['mailpost']?></span>
                <?php endif ?>
            </p>
            <p>
                <label>
                    <span>message</span>
                    <textarea name="message"><?= !empty($_POST['message'])? $_POST['message'] : ''?></textarea>
                </label>
                <?php if(isset($_POST['error']['message'])): ?>
                <span class="error"><?= $_POST['error']['message']?></span>
                <?php endif ?>
            </p>
            <p><button type="submit" class="button">envoyer</button></p>
        </form>
    </div>
</body>
</html>


Pour répondre à tes 2 questions, lis la doc php à ces sujets Smiley cligne
Modifié par niuxe (28 May 2024 - 22:42)
QuentinC a écrit :
Bonsoir,

En réalité, on fait complètement fausse route avec les CAPTCHA. Il faut les bannir, bientôt ils seront complètement inutiles.

Et sans doute bientôt interdit par la commission européenne, justement pour cause d'intrusion dans la vie privée. Ce qui rejoint ce que tu pointes à leur sujet.
Bonjour,
Avec un peu de retard, je découvre ce fil.
J'avais également le problème du formulaire reçu vide alors que les champs à compléter sont bien évidemment "obligés" ...
Finalement j'ai compris (du moins je le pense) que les supposés robots passaient directement par le lien php de validation du formulaire, par exemple :
<form method="post" enctype="multipart/form-data" action="redir-contact.php" name="formmail">

Du coup, et de façon radicale, dans ce php de validation j'ai mis un exit si un des champs obligatoire n'est pas rempli :
if (empty($_POST['mail']))
exit;
Ce qui fait que l'on reste sur une page blanche et plus de risque de valider un formulaire vide..
Le visiteur "normal" lui, ne sera pas arrivé jusque là puisque le champ Mail est obligatoire en complétant le formulaire...
C'est sans doute empirique (suis pas un pro du php), mais ça fonctionne... Smiley lol
Avis ? Inconvénients ? Merci...
Modifié par Charlie-82 (08 Sep 2024 - 09:35)
Salut

J'utilise non seulement une solution ressemblant à celle de Charlie, mais également les Token CSRF

je créer un token unique sur un session start :
// Commencez la session
session_start();

// Générer un token CSRF unique
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}


Je le met dans le formulaire :

<form method="post" action="redir-contact.php" name="formmail">
    <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
    <!-- autres champs du formulaire -->
    <input type="email" name="mail" required>
    <input type="submit" value="Envoyer">
</form>



et à la soumission du formulaire de vérifie :

// Vérifiez si le token est valide
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
        die('Erreur CSRF. La requête est rejetée.');
    }

    // Continuez avec le traitement du formulaire si le token est valide
    $mail = $_POST['mail'] ?? '';
    if (empty($mail)) {
        die('Le champ email est requis.');
    }

    // Traitement du formulaire
    echo 'Formulaire soumis avec succès.';
}


Si ça passe pas, alors pas de mail().