Aller au contenu principal

Guide d’intégration

Lookups de menaces pour Splunk issus des listes isMalicious

Une entrée scriptée récupère chaque liste avec votre clé API, refuse l’échantillon de 10 % et reconstruit un lookup CSV toutes les 12 heures. Enterprise Security lit une copie interne ; l’envoi par HEC pousse les IOC à la demande.

Aucune carte bancaire requise · Clé API gratuite

Chemin des données
  1. isMalicious

    api.ismalicious.com

    blocklist-ips-critical.txt

    Régénérée toutes les 12 h

  2. Lookups Splunk et ES

    Étape 3

    Ajouter le script de récupération

  3. Rapprocher vos événements des listes

    Étape 5
Sur cette page08

Ce que vous obtenez

Un lookup comme une threat list ES lit un indicateur par ligne : les listes simples conviennent. Commencez par les IP de niveau critical et les listes par catégorie ; n’ajoutez les domaines de niveau critical qu’après avoir dimensionné le lookup.

ListeEntréesRégénéréeOffres
blocklist-ips-critical.txtPar défaut. IP signalées par 6 sources de menaces ou plus, ou par 3 ou plus avec une catégorie critique.environ 89 000toutes les 12 hToutes les offres payantes
blocklist-ips-c2.txtIP de commande et contrôle (C2) signalées par des trackers de C2, quel que soit leur niveau.environ 44 000toutes les 12 hToutes les offres payantes
blocklist-domains-c2.txtDomaines de commande et contrôle (C2) signalés par des trackers de C2, quel que soit leur niveau.environ 22 000toutes les 12 hToutes les offres payantes
blocklist-domains-ransomware.txtDomaines de la catégorie ransomware, quel que soit leur niveau.environ 3 600toutes les 12 hToutes les offres payantes
blocklist-domains-critical.txtSeulement après dimensionnement : une ligne de lookup ou un enregistrement ES par entrée.environ 2 millionstoutes les 12 hToutes les offres payantes
/app/integrations/splunkIOC et événements SOC poussés vers votre HTTP Event Collector, en sourcetypes ismalicious:ioc et ismalicious:soc. Ce n’est pas un flux : voir Limites.jusqu’à 1 000 par synchronisationà la synchronisationPro et Enterprise

Nombres arrondis d’après la génération du  ; chaque liste est régénérée toutes les 12 heures. Les chiffres du jour sont publics et ne demandent aucune clé.

Ce que reçoit chaque offre

  • FreeCompte Free, ou aucune clé : les premiers 10 % de chaque liste, signalés par X-Blocklist-Version: lite.
  • Toutes les offres payantesOffres payantes : toutes les listes, complètes.
  • Pro et EnterpriseCollections TAXII 2.1, pour les plateformes qui lisent les indicateurs STIX : Pro et Enterprise.
  • Pro et EnterpriseDestinations SIEM du tableau de bord (Splunk, Elastic, Sentinel) : Pro et Enterprise.

Comparer les offres

Ce que renvoie un téléchargementHTTP

GET https://api.ismalicious.com/blocklist/download/blocklist-ips-critical.txt

Liste complète ou échantillon de 10 %

ChampToutes les offres payantesFree
X-Blocklist-Version:fulllite
X-Blocklist-Percentage:10010
Total entries:<COUNT><COUNT> (Lite Version - 10% of <TOTAL>)

Premières lignes du fichier

# IsMalicious.com Blocklist - IPs (Critical)
# Format: Plain
# Generated: <BUILD_TIME>
# Total entries: <COUNT>
# Update frequency: every 12 hours
# Category: All
# Threat level: Critical
# Website: https://ismalicious.com
# © <YEAR> IsMalicious (compilation). Licensed to the downloading account under https://ismalicious.com/terms; redistribution of the compilation prohibited. Third-party entries remain under their providers' licences — see https://ismalicious.com/sources.
#

Les valeurs entre chevrons sont fixées à chaque génération.

Prérequis

  • Splunk Enterprise 9.x ou 10.x pour les lookups. Sur Splunk Cloud Platform, les fichiers .conf ne se modifient pas directement : voir les limites.
  • Un shell sur le search head, avec curl et awk.
  • Une clé API et son secret isMalicious, dans Compte › Accès API.
  • Un accès HTTPS sortant (TCP 443) en IPv4 depuis le search head Splunk vers api.ismalicious.com, qui n’a pas d’adresse IPv6.

Mise en place

  1. Copier la clé API et le secret

    Ouvrez Compte › Accès API et copiez la Clé API et le Secret API. La liste complète demande une offre payante ; une clé Free reçoit l’échantillon de 10 %, que le script refuse.
  2. Créer l’app et son fichier d’identifiants

    Sur le search head, créez $SPLUNK_HOME/etc/apps/ismalicious_lists/ avec bin/, local/ et lookups/. Écrivez la clé et le secret dans local/ismalicious.netrc, propriété de l’utilisateur Splunk, en mode 600 : curl les lit dans le fichier, pas sur la ligne de commande.
    local/ismalicious.netrcnetrc
    machine api.ismalicious.com login <API_KEY> password <API_SECRET>
  3. Ajouter le script de récupération

    Enregistrez-le sous bin/fetch_ismalicious.sh, en mode 755. Il télécharge la liste, refuse une erreur, un contenu qui n’est pas une liste, l’échantillon de 10 % et un fichier dont le nombre d’entrées diffère de son en-tête, écrit un lookup CSV à deux colonnes sans les lignes d’en-tête #, et affiche une ligne d’état : status=ok avec le nombre de lignes, ou status=refused, la raison allant dans splunkd.log. Une liste refusée garde le lookup précédent.
    bin/fetch_ismalicious.shsh
    #!/bin/sh
    # Rebuilds lookups/$NAME.csv from $LIST and prints one status line, which the
    # scripted input indexes. Copy it per list: for a domain list, set FIELD=domain.
    set -eu
    APP_DIR=$(cd "$(dirname "$0")/.." && pwd)
    NETRC="$APP_DIR/local/ismalicious.netrc"
    LIST=blocklist-ips-critical.txt
    NAME=ismalicious_ips
    FIELD=ip
    RAW=$(mktemp)
    TMP=$(mktemp "$APP_DIR/lookups/.$NAME.csv.XXXXXX")
    trap 'rm -f "$RAW" "$TMP"' EXIT
    
    # fetch_list LIST OUT: download one list to OUT and check it.
    # On any failure OUT is removed and the function returns 1.
    fetch_list() {
      if ! code=$(curl --silent --show-error --fail --netrc-file "$NETRC" \
          --proto '=https' --max-time 300 --retry 2 \
          --output "$2" --write-out '%{http_code}' "https://api.ismalicious.com/blocklist/download/$1"); then
        rm -f "$2"; echo "$1: download failed" >&2; return 1
      fi
      if [ "$code" != 200 ]; then
        rm -f "$2"; echo "$1: HTTP $code" >&2; return 1
      fi
      if ! head -n 1 "$2" | grep -q '^[#!] IsMalicious.com Blocklist'; then
        rm -f "$2"; echo "$1: not an isMalicious list" >&2; return 1
      fi
      if grep -q 'Lite Version' "$2"; then
        rm -f "$2"; echo "$1: lite list received, check the API key and the plan" >&2
        return 1
      fi
      # Every entry ends with a newline, and one header counts them: refuse a
      # cut, doubled or empty file.
      if [ -n "$(tail -c 1 "$2")" ]; then
        rm -f "$2"; echo "$1: cut short, no final newline" >&2; return 1
      fi
      if [ "$(grep -c '^[#!] Total entries:' "$2")" != 1 ]; then
        rm -f "$2"; echo "$1: not one Total entries line" >&2; return 1
      fi
      total=$(sed -n 's/^[#!] Total entries: \([0-9,]*\)$/\1/p' "$2" | tr -d ,)
      got=$(grep -c '^[^#!]' "$2" || true)
      if [ -z "$total" ] || [ "$total" = 0 ] || [ "$got" != "$total" ]; then
        rm -f "$2"; echo "$1: $got entries, the header says ${total:-none}" >&2
        return 1
      fi
    }
    
    # On any failure the previous lookup stays; the reason goes to splunkd.log.
    if ! fetch_list "$LIST" "$RAW"; then
      echo "ismalicious_fetch status=refused list=$LIST"
      exit 1
    fi
    
    awk -v field="$FIELD" -v list="${LIST%.txt}" 'BEGIN { print field ",ismalicious_list" }
      !/^[#!]/ && NF { print $1 "," list }' "$RAW" > "$TMP"
    chmod 644 "$TMP"
    mv -f "$TMP" "$APP_DIR/lookups/$NAME.csv"
    echo "ismalicious_fetch status=ok list=$LIST rows=$(($(wc -l < "$APP_DIR/lookups/$NAME.csv") - 1))"
  4. Le planifier et déclarer le lookup

    Ajoutez les deux stanzas sous local/, puis redémarrez Splunk. L’entrée scriptée s’exécute deux fois par jour ; un intervalle cron ne s’exécute pas au démarrage : lancez donc le script une première fois à la main.
    local/inputs.confconf
    [script://./bin/fetch_ismalicious.sh]
    # The lists are rebuilt every 12 hours. A cron interval does not run at start-up.
    interval = 17 3,15 * * *
    index = <INDEX>
    sourcetype = ismalicious:fetch
    disabled = 0
    local/transforms.confconf
    [ismalicious_ips]
    filename = ismalicious_ips.csv
    
    # A domain lookup built the same way (FIELD=domain):
    [ismalicious_domains]
    filename = ismalicious_domains.csv
    case_sensitive_match = false
  5. Faites le lookup sur le champ d’adresse de vos événements de pare-feu ou de proxy. Les lookups comparent des valeurs exactes : normalisez d’abord le champ.
    RechercheSPL
    index=<FIREWALL_INDEX> sourcetype=<FIREWALL_SOURCETYPE>
    | lookup ismalicious_ips ip AS dest_ip OUTPUT ismalicious_list
    | where isnotnull(ismalicious_list)
  6. Dans Enterprise Security, ajouter une source Line Oriented (facultatif)

    • Servez à ES, en HTTPS, une copie récupérée sur un hôte que vous contrôlez avec le script ci-dessous, qui applique les mêmes vérifications, et donnez à ES cette URL, sans identifiant.
    • Dans ES 8, interface en anglais : Configure › Threat intelligence › Data sources › + Data source › Line Oriented.
    • Name ismalicious_ips_critical, Type threatlist_ip, l’URL de votre copie, Interval 43200, Delimiting regular expression ,, Skip header lines 0, et gardez l’Ignoring regular expression par défaut, qui saute les lignes #.
    • Ajoutez une source par liste avec les Fields ci-dessous, puis activez les recherches de threat matching utiles.
    Copie pour Enterprise Securitysh
    #!/bin/sh
    # Every 12 hours from cron, on a host ES reaches over HTTPS.
    # /etc/ismalicious/netrc (mode 600) holds the three netrc lines.
    set -eu
    NETRC=/etc/ismalicious/netrc
    DIR=/var/www/blocklists
    FILE=blocklist-ips-critical.txt
    
    # fetch_list LIST OUT: download one list to OUT and check it.
    # On any failure OUT is removed and the function returns 1.
    fetch_list() {
      if ! code=$(curl --silent --show-error --fail --netrc-file "$NETRC" \
          --proto '=https' --max-time 300 --retry 2 \
          --output "$2" --write-out '%{http_code}' "https://api.ismalicious.com/blocklist/download/$1"); then
        rm -f "$2"; echo "$1: download failed" >&2; return 1
      fi
      if [ "$code" != 200 ]; then
        rm -f "$2"; echo "$1: HTTP $code" >&2; return 1
      fi
      if ! head -n 1 "$2" | grep -q '^[#!] IsMalicious.com Blocklist'; then
        rm -f "$2"; echo "$1: not an isMalicious list" >&2; return 1
      fi
      if grep -q 'Lite Version' "$2"; then
        rm -f "$2"; echo "$1: lite list received, check the API key and the plan" >&2
        return 1
      fi
      # Every entry ends with a newline, and one header counts them: refuse a
      # cut, doubled or empty file.
      if [ -n "$(tail -c 1 "$2")" ]; then
        rm -f "$2"; echo "$1: cut short, no final newline" >&2; return 1
      fi
      if [ "$(grep -c '^[#!] Total entries:' "$2")" != 1 ]; then
        rm -f "$2"; echo "$1: not one Total entries line" >&2; return 1
      fi
      total=$(sed -n 's/^[#!] Total entries: \([0-9,]*\)$/\1/p' "$2" | tr -d ,)
      got=$(grep -c '^[^#!]' "$2" || true)
      if [ -z "$total" ] || [ "$total" = 0 ] || [ "$got" != "$total" ]; then
        rm -f "$2"; echo "$1: $got entries, the header says ${total:-none}" >&2
        return 1
      fi
    }
    
    mkdir -p "$DIR"
    tmp=$(mktemp "$DIR/.$FILE.XXXXXX")
    trap 'rm -f "$tmp"' EXIT
    fetch_list "$FILE" "$tmp"
    chmod 644 "$tmp"
    mv -f "$tmp" "$DIR/$FILE"
    
    # ES source URL: https://<INTERNAL_HOST>/blocklists/blocklist-ips-critical.txt
    Fields ES, par listeSplunk ES

    # Line Oriented sources, one per list: the file, then its Fields.

    blocklist-ips-critical.txt
    ip:$1,description:isMalicious_ips_critical
    blocklist-ips-c2.txt
    ip:$1,description:isMalicious_ips_c2
    blocklist-domains-c2.txt
    domain:$1,description:isMalicious_domains_c2
    blocklist-domains-ransomware.txt
    domain:$1,description:isMalicious_domains_ransomware

    # URL and hash lists route to http_intel and file_intel. /blocklist/stats does

    # not count them: read a file's Total entries line before you add it.

    blocklist-urls-critical.txt
    url:$1,description:isMalicious_urls_critical
    blocklist-hashes-malware.txt
    file_hash:$1,description:isMalicious_hashes_malware
    # Line Oriented sources, one per list: the file, then its Fields.
    blocklist-ips-critical.txt        ip:$1,description:isMalicious_ips_critical
    blocklist-ips-c2.txt              ip:$1,description:isMalicious_ips_c2
    blocklist-domains-c2.txt          domain:$1,description:isMalicious_domains_c2
    blocklist-domains-ransomware.txt  domain:$1,description:isMalicious_domains_ransomware
    
    # URL and hash lists route to http_intel and file_intel. /blocklist/stats does
    # not count them: read a file's Total entries line before you add it.
    blocklist-urls-critical.txt       url:$1,description:isMalicious_urls_critical
    blocklist-hashes-malware.txt      file_hash:$1,description:isMalicious_hashes_malware
  7. Ou, dans ES 8.2 ou ultérieur, ajouter une source TAXII 2 (non testé)

    • ES 8.2 et ultérieur téléchargent les collections TAXII 2.0 et 2.1. Pour les documents STIX, Splunk documente son analyse STIX 2 pour les objets observables tels que observed-data et indique que la syntaxe de pattern des objets indicator n’est pas prise en charge ; ce guide suppose que la source TAXII 2 utilise le même analyseur. Chaque collection isMalicious a donc sa variante d’observables, à l’identifiant suivi de -observables, qui sert chaque indicateur sous forme d’objet observed-data : c’est elle qu’il faut donner à ES.
    • Cette source ne supprime jamais un indicateur qu’isMalicious a retiré : Splunk indique que les flux TAXII 2 n’utilisent pas le réglage Maximum age, et la variante d’observables ne porte aucun retrait. Les listes, elles, le suppriment, parce que chaque téléchargement est un instantané complet : le lookup à sa reconstruction suivante, les sources Line Oriented d’ES une fois leur Maximum age écoulé. Préférez-les.
    • Dans Configure › General settings › Credentials, sélectionnez New credential : la clé API en Username, le secret API en Password, et le contexte d’app, par exemple Enterprise Security.
    • Dans Configure › Threat intelligence › Data sources, sélectionnez + Data source, saisissez un Name, une Description et l’URL de collection ci-dessous, laissez Threat Intelligence coché, et sélectionnez l’identifiant dans l’onglet Advanced.
    • L’argument POST earliest fixe jusqu’où remonte le premier téléchargement ; les suivants partent de l’exécution précédente.
    • Après le premier téléchargement, Analytics › Audit › Threat intelligence audit affiche la source ; comptez ses enregistrements dans ip_intel avant de vous y fier. Ce chemin n’a pas été testé dans ES lui-même.
    Source TAXII 2Splunk ES
    Collection URL
    https://api.ismalicious.com/taxii/api-root/collections/c2-indicators-observables/
    POST arguments
    earliest="-30d"
    Collection URL .. https://api.ismalicious.com/taxii/api-root/collections/c2-indicators-observables/
    POST arguments .. earliest="-30d"
  8. Pousser les IOC par HEC (facultatif, offre Pro ou Enterprise)

    • Dans Splunk, Settings › Add Data › Monitor › HTTP Event Collector : nom ismalicious, sélectionnez l’index autorisé, Review, Submit, et copiez le jeton ; dans Global Settings, passez All Tokens sur Enabled.
    • HEC doit présenter un certificat d’une autorité publique : le certificat HEC par défaut de Splunk est autosigné et refusé, réglez donc serverCert dans la stanza [http] d’inputs.conf, ou placez HEC derrière un répartiteur de charge qui en a un.
    • Dans /app/integrations/splunk, saisissez l’URL HEC (https://, port 8088, chemin /services/collector), le Jeton HEC et l’Index.
    • Cliquez sur Tester, puis sur Synchroniser maintenant : chaque synchronisation envoie jusqu’à 1 000 IOC (100 par défaut) à partir de l’endroit où la précédente s’est arrêtée, et les événements SOC partent dans les cinq minutes.

Vérifier le résultat

  • | inputlookup ismalicious_ips | stats count correspond au count de la liste dans /blocklist/stats, à une régénération près.
  • Les événements ismalicious:fetch donnent l’état et le nombre de lignes de chaque exécution. status=lite signifie que la clé n’a pas obtenu la liste complète : le lookup précédent a été conservé.
  • Dans ES, Analytics › Audit › Threat intelligence audit indique la source comme téléchargée, et le nombre d’entrées ip_intel de son threat_key correspond à la liste.
  • Après une synchronisation, sourcetype="ismalicious:ioc" contient les IOC, et la page de l’intégration liste chaque livraison.
RecherchesSPL
| inputlookup ismalicious_ips | stats count

index=<INDEX> sourcetype=ismalicious:fetch
| table _time status list rows

| inputlookup ip_intel | search threat_key=ismalicious_ips_critical | stats count

index=<INDEX> sourcetype="ismalicious:ioc" | stats count by event.entityType

Dépannage

La récupération échoue avec une erreur 401

La clé ou le secret du fichier netrc est faux ou incomplet : le script journalise status=refused, splunkd.log affiche « download failed », et le lookup précédent reste en place. Le corps de la réponse indique « Blocklist not found or empty » ; fiez-vous au code HTTP. Recopiez les deux valeurs depuis Compte › Accès API.

« lite list received » dans splunkd.log

L’offre est Free ou interrompue : un abonnement impayé, en retard de paiement, annulé, incomplet ou suspendu compte comme Free. Le script journalise status=refused et garde le lookup précédent jusqu’à ce que la clé obtienne la liste complète.

« entries, the header says », « cut short, no final newline » ou « not one Total entries line » dans splunkd.log

Le fichier était vide, tronqué ou n’était pas une des listes, comme quand un proxy ou un portail captif répond. Le script garde le lookup précédent ; l’exécution suivante réessaie.

Délai dépassé ou erreur 502

Un téléchargement qui prend plus de 30 secondes de notre côté finit en délai dépassé ou en 502 : prenez une liste par niveau ou par catégorie du tableau.

503 Service Unavailable

La liste est en cours de première génération, et la réponse porte Retry-After: 600. Le script échoue, garde le lookup précédent, et l’exécution suivante récupère la liste.

Lignes d’en-tête dans le lookup ou dans ES

Un lookup ne peut pas contenir l’en-tête # : c’est pourquoi le script retire ces lignes. ES les saute avec son Ignoring regular expression par défaut : rétablissez-la si vous l’avez modifiée.

Une valeur listée ne correspond pas

Les lookups comparent des valeurs exactes, en respectant la casse par défaut. Normalisez le champ de l’événement, et réglez case_sensitive_match = false sur un lookup de domaines.

Erreurs de certificat

curl vérifie le magasin de certificats du système. Mettez-le à jour, vérifiez l’horloge et exemptez api.ismalicious.com de l’inspection TLS.

La destination HEC est refusée ou les livraisons échouent

L’URL HEC doit être une adresse HTTPS publique avec un certificat d’une autorité publique : les adresses privées et de bouclage sont refusées à l’enregistrement, et le certificat autosigné par défaut de Splunk fait échouer chaque livraison. Chaque livraison doit recevoir une réponse en moins de 5 secondes, et le jeton doit autoriser l’index saisi.

Limites

  • Le chemin TAXII 2 ne supprime pas ce qu’isMalicious retire : Splunk indique que les flux TAXII 2 n’utilisent pas le réglage Maximum age, et la variante d’observables ne porte aucun retrait, si bien qu’un faux positif nettoyé dans isMalicious reste dans ES. Les listes le suppriment, puisque chaque téléchargement est un instantané complet : préférez-les. Ce chemin n’a pas non plus été testé dans ES. Pour les documents STIX, Splunk documente l’analyse des observables, pas des patterns d’indicateurs, d’où la variante -observables d’une collection ; la façon dont la source TAXII 2 envoie l’identifiant n’est pas documentée, et le rangement des observables dans les collections de threat intelligence se règle dans le collections.conf d’ES.
  • L’envoi par HEC n’est pas un flux : il part quand vous cliquez sur Synchroniser maintenant, envoie au plus 1 000 IOC par synchronisation, et rien ne le planifie.
  • L’option d’identifiant d’ES pour les sources URL n’est pas couverte ici : donnez à ES une copie interne.
  • Aucun fichier CSV, JSON, CIDR ou générique n’est servi. Le script construit le lookup CSV dont Splunk a besoin, et les types de correspondance CIDR et WILDCARD de Splunk n’ont rien à comparer dans les listes.
  • Sur Splunk Cloud Platform, les fichiers .conf ne se modifient pas directement : empaquetez bin/, local/ et lookups/ en app privée et installez-la après validation AppInspect (Victoria Experience ; non testé pour ce guide), importez le lookup à la main dans Settings › Lookups, ou utilisez l’envoi par HEC.
  • Les clusters de search heads ne sont pas couverts : déployez l’app depuis le deployer plutôt que d’écrire des lookups sur un seul membre.
  • Les listes d’URL et de hashs existent sous les mêmes noms, mais /blocklist/stats ne les compte pas : lisez la ligne Total entries d’un fichier avant de vous en servir.
  • L’échantillon de 10 % est le premier dixième d’un fichier non trié, pas le dixième le plus risqué.

Questions fréquentes

Splunk Enterprise Security peut-il utiliser le flux TAXII d’isMalicious ?

Cela n’a pas été testé. ES 8.2 et ultérieur téléchargent les collections TAXII 2.0 et 2.1, et pour les documents STIX, Splunk documente l’analyse des objets observed-data, pas des patterns des objets indicator. Chaque collection isMalicious a une variante d’observables, à l’identifiant suivi de -observables, qui sert des observed-data : c’est la collection à donner à ES, comme dans l’étape TAXII 2. Cette source ne supprime jamais un indicateur qu’isMalicious a retiré. Les listes, chargées en sources Line Oriented, le font et fonctionnent sur toutes les versions : préférez-les.

Est-ce que cela fonctionne sur Splunk Cloud Platform ?

Pas tel quel : Splunk Cloud Platform ne permet pas de modifier directement les fichiers .conf. Une app privée contenant le script, ses entrées et le lookup peut y tourner après validation AppInspect (Victoria Experience ; non testé pour ce guide) ; sinon, importez le lookup à la main, ou utilisez l’envoi par HEC depuis le tableau de bord, avec une offre Pro ou Enterprise, qui envoie jusqu’à 1 000 IOC par synchronisation.

À quelle fréquence le lookup est-il rafraîchi ?

Deux fois par jour, selon l’intervalle cron d’inputs.conf. Les listes sont régénérées toutes les 12 heures : une exécution plus fréquente retélécharge le même fichier. Un intervalle cron ne s’exécute pas au démarrage.

Que se passe-t-il avec une clé API gratuite ?

Le téléchargement est l’échantillon de 10 %, et le script le refuse : il journalise status=refused et garde le lookup précédent. La liste complète demande une offre payante.

Pourquoi un domaine listé ne correspond-il pas à mes événements ?

Les lookups comparent des valeurs exactes et respectent la casse par défaut. Réglez case_sensitive_match = false sur le lookup de domaines, et normalisez le champ de l’événement avant le lookup.

Commencer

Prêt à commencer ?

Aucune carte bancaire requise · Clé API gratuite