RO

Tema

Culoarea de accent

Tema și culoarea te urmează pe satelit.md și în aplicație.

Panou Alege un plan

Satelit Shield, de la script la server.

Baza este https://api.satelit.md/shield/v1. Pagina folosește cheia publică a site-ului; serverul tău trimite secretul în Authorization: Bearer shs_….

  1. Adaugă site-ul și ia cheile

    În panou adaugi site-ul și domeniile lui. Primești cheia site-ului, publică (shp_ și 24 de caractere), și secretul (shs_ și 40), pe care îl vezi o singură dată.

    Protejează-ți site-ulProtejează-ți site-ul

  2. Pune senzorul pe pagini

    Direct sau prin proxy first-party. Un site nou pornește cu toate regulile în observare (shadow).

    <!-- in every page, direct -->
    <script src="https://api.satelit.md/shield/v1/sensor.js"
      data-site="shp_XXXXXXXXXXXXXXXXXXXXXXXX" async></script>
    # Caddyfile: /_sh/* goes to Shield, with your secret and the visitor's address
    example.md {
    	handle_path /_sh/* {
    		rewrite * /shield/v1{uri}
    		reverse_proxy https://api.satelit.md {
    			header_up Host {upstream_hostport}
    			header_up X-Shield-Secret {env.SHIELD_SECRET}
    			header_up X-Shield-Client-IP {client_ip}
    			header_up -Cookie
    			header_up -Authorization
    		}
    	}
    	# ... the rest of your site
    }
    
    # in every page:
    # <script src="/_sh/sensor.js" data-site="shp_XXXXXXXXXXXXXXXXXXXXXXXX" data-base="/_sh" async></script>
    # nginx: /_sh/ goes to Shield, with your secret and the visitor's address
    location /_sh/ {
        proxy_pass https://api.satelit.md/shield/v1/;
        proxy_ssl_server_name on;
        proxy_set_header Host api.satelit.md;
        proxy_set_header X-Shield-Secret "shs_...";        # keep this file out of your repository
        proxy_set_header X-Shield-Client-IP $remote_addr;  # behind Cloudflare: $http_cf_connecting_ip
        proxy_set_header Cookie "";
        proxy_set_header Authorization "";
    }
    
    # in every page:
    # <script src="/_sh/sensor.js" data-site="shp_XXXXXXXXXXXXXXXXXXXXXXXX" data-base="/_sh" async></script>
  3. Citește evenimentele, apoi pornește protecția

    În panou vezi ce ar fi oprit fiecare regulă. Treci pe enforce regulile în care ai încredere.

Atributele scriptului

AtributCe face
data-siteObligatoriu. Cheia publică a site-ului.
data-baseUnde trimite senzorul rapoartele. Implicit: dosarul din care s-a încărcat scriptul; prin proxy first-party, /_sh.
data-overlay="0"0: senzorul nu desenează niciodată verificarea în pagină; serverul tău servește pagina de verificare.
HTML
<!-- in every page, direct -->
<script src="https://api.satelit.md/shield/v1/sensor.js"
  data-site="shp_XXXXXXXXXXXXXXXXXXXXXXXX" async></script>

Proxy first-party

Serverul tău trimite /_sh/* la https://api.satelit.md/shield/v1/*, adaugă X-Shield-Secret și X-Shield-Client-IP (și, dacă vrei, X-Shield-Client-Country) și lasă neschimbate User-Agent, Accept-Language, Sec-Fetch-* și Sec-CH-UA*. Adresa clientului este crezută doar împreună cu secretul corect. Cookie-urile vizitatorilor nu trebuie să plece spre Shield.

# Caddyfile: /_sh/* goes to Shield, with your secret and the visitor's address
example.md {
	handle_path /_sh/* {
		rewrite * /shield/v1{uri}
		reverse_proxy https://api.satelit.md {
			header_up Host {upstream_hostport}
			header_up X-Shield-Secret {env.SHIELD_SECRET}
			header_up X-Shield-Client-IP {client_ip}
			header_up -Cookie
			header_up -Authorization
		}
	}
	# ... the rest of your site
}

# in every page:
# <script src="/_sh/sensor.js" data-site="shp_XXXXXXXXXXXXXXXXXXXXXXXX" data-base="/_sh" async></script>
# nginx: /_sh/ goes to Shield, with your secret and the visitor's address
location /_sh/ {
    proxy_pass https://api.satelit.md/shield/v1/;
    proxy_ssl_server_name on;
    proxy_set_header Host api.satelit.md;
    proxy_set_header X-Shield-Secret "shs_...";        # keep this file out of your repository
    proxy_set_header X-Shield-Client-IP $remote_addr;  # behind Cloudflare: $http_cf_connecting_ip
    proxy_set_header Cookie "";
    proxy_set_header Authorization "";
}

# in every page:
# <script src="/_sh/sensor.js" data-site="shp_XXXXXXXXXXXXXXXXXXXXXXXX" data-base="/_sh" async></script>

API-ul JavaScript

  • SatelitShield.ready(fn): fn({a, t, explain}) după primul raport al paginii. a: '' nimic, 'g' verificare, 'b' oprit.
  • SatelitShield.token(fn): fn(token) cu un token de verdict nou, pentru un formular sau un apel API. Îl verifici pe server.
  • SatelitShield.version: versiunea senzorului.
  • Evenimentul satelit-shield pe document, cu același detail ca ready.
JavaScript
// after the page's first report
SatelitShield.ready(function (r) {
  // r.a: "" nothing, "g" a check, "b" blocked; r.t: a verdict token
});
document.addEventListener("satelit-shield", function (e) {
  console.log(e.detail.a, e.detail.t);
});

// a fresh token goes with the form, in a hidden field
form.addEventListener("submit", function (e) {
  e.preventDefault();
  SatelitShield.token(function (token) {
    form.elements.shield_token.value = token;
    form.submit();
  });
});

Pagina de verificare și pagina de oprire

Modul paginii vine din atributul data-shield al elementului html. Fără atribut: o pagină obișnuită. check: pagina ta de verificare, cu statusul 429; senzorul o rezolvă, păstrează permisul și reîncarcă aceeași adresă. ban: pagina cu statusul 403; senzorul doar o traduce.

429
<!doctype html>
<html lang="ro" data-shield="check">
<head>
  <meta charset="utf-8">
  <meta content="noindex" name="robots">
  <script src="/_sh/sensor.js" data-site="shp_XXXXXXXXXXXXXXXXXXXXXXXX" data-base="/_sh" async></script>
</head>
<body><p>Se verifică browserul.</p></body>
</html>

Cookie-urile

  • __shpPermisul după o verificare rezolvată: p1.{exp}.{token}.{sig}.
  • __shs1: browserul a rulat senzorul (400 de zile), ca un cititor care revine să nu fie socotit fără dovadă.

Amândouă sunt first-party, pe domeniul tău: SameSite=Lax, Secure pe https, calea /.

Permisul, verificat la tine

Un permis se verifică pe serverul tău, fără niciun apel către Shield.

  • Cheia permisului: HMAC-SHA256(key = sha256_hex(secret), "satelit-shield-pass-v1"), în hex. O calculezi o dată.
  • sig sunt primele 22 de caractere din base64url(HMAC-SHA256(cheia permisului, "p1|{exp}|{token}|{client key}|{User-Agent}")); exp în secunde unix, token 16 caractere hex.
  • Permisul e valabil cât exp nu a trecut și semnătura se potrivește cu cheia clientului și User-Agent-ul acestei cereri: un permis copiat pe altă adresă sau în alt browser nu deschide nimic.
  • Durata: 12 ore; 2 ore pentru clienții cu risc (Tor, o rețea de hosting, o flotă, o decizie dură în ultimele 7 zile). Un permis deschide o verificare, niciodată o oprire.
// Satelit Shield: check a pass (the __shp cookie) on your own server, with no call to Shield. Node 18+.
// A pass is p1.{exp}.{token}.{sig}; sig is the first 22 characters of
// base64url(HMAC-SHA256(pass key, "p1|{exp}|{token}|{client key}|{User-Agent}")).
import { createHash, createHmac, timingSafeEqual } from "node:crypto";

// The pass key: HMAC-SHA256 with the key sha256_hex(secret) over "satelit-shield-pass-v1", in hex.
export function passKey(secret) {
  const key = createHash("sha256").update(secret).digest("hex");
  return createHmac("sha256", key).update("satelit-shield-pass-v1").digest("hex");
}

// The client key: an IPv4 address as it is, an IPv6 address as its /64 (the first four groups and "::").
export function clientKey(ip) {
  const v4 = /^(?:::ffff:)?(\d{1,3}(?:\.\d{1,3}){3})$/i.exec(ip);
  if (v4) return v4[1];
  const [head, tail = ""] = ip.toLowerCase().split("%")[0].split("::");
  const a = head ? head.split(":") : [];
  const b = tail ? tail.split(":") : [];
  const groups = [...a, ...Array(Math.max(0, 8 - a.length - b.length)).fill("0"), ...b];
  return groups.slice(0, 4).map((g) => parseInt(g, 16).toString(16)).join(":") + "::";
}

// True when the pass has not expired and was signed for this address and this browser.
export function passValid(pass, secret, ip, userAgent, now = Date.now() / 1000) {
  const m = /^p1\.(\d+)\.([0-9a-f]{16})\.([A-Za-z0-9_-]{22})$/.exec(pass ?? "");
  if (!m || Number(m[1]) <= now) return false;
  const message = `p1|${m[1]}|${m[2]}|${clientKey(ip)}|${userAgent}`;
  const sig = createHmac("sha256", passKey(secret)).update(message).digest("base64url").slice(0, 22);
  return timingSafeEqual(Buffer.from(sig), Buffer.from(m[3]));
}
"""Satelit Shield: check a pass (the __shp cookie) on your own server, with no call to Shield. Python 3.8+.

A pass is p1.{exp}.{token}.{sig}; sig is the first 22 characters of
base64url(HMAC-SHA256(pass key, "p1|{exp}|{token}|{client key}|{User-Agent}")).
"""
import base64
import hashlib
import hmac
import ipaddress
import re
import time

PASS = re.compile(r"p1\.(\d+)\.([0-9a-f]{16})\.([A-Za-z0-9_-]{22})")


def pass_key(secret):
    """HMAC-SHA256 with the key sha256_hex(secret) over "satelit-shield-pass-v1", in hex."""
    key = hashlib.sha256(secret.encode()).hexdigest().encode()
    return hmac.new(key, b"satelit-shield-pass-v1", hashlib.sha256).hexdigest()


def client_key(ip):
    """An IPv4 address as it is, an IPv6 address as its /64 (the first four groups and "::")."""
    a = ipaddress.ip_address(ip.split("%")[0])
    if a.version == 6 and a.ipv4_mapped:
        a = a.ipv4_mapped
    if a.version == 4:
        return str(a)
    return ":".join(format(int(g, 16), "x") for g in a.exploded.split(":")[:4]) + "::"


def pass_valid(value, secret, ip, user_agent, now=None):
    """True when the pass has not expired and was signed for this address and this browser."""
    m = PASS.fullmatch(value or "")
    if not m or int(m[1]) <= (time.time() if now is None else now):
        return False
    message = f"p1|{m[1]}|{m[2]}|{client_key(ip)}|{user_agent}".encode()
    mac = hmac.new(pass_key(secret).encode(), message, hashlib.sha256).digest()
    sig = base64.urlsafe_b64encode(mac).decode().rstrip("=")[:22]
    return hmac.compare_digest(sig, m[3])

Cheia clientului

Adresa IPv4 ca atare; la IPv6, rețeaua /64, scrisă ca primele patru grupuri urmate de :: (2a01:4f8:221:1f15::). Opririle, verificările, permisele și contoarele sunt pe cheia clientului.

Apelurile de server

Toate cer Authorization: Bearer shs_… și se fac doar de pe server.

POST /verify

Verifică un token de verdict. Un token trăiește 300 de secunde și se verifică o singură dată; altfel success e false, cu error: used, expired, invalid sau other_ip. Cu ip, un token de la altă cheie de client e refuzat. score: de la 0, un om, la 100, un bot sigur.

POST /verify
curl https://api.satelit.md/shield/v1/verify \
  -H "Authorization: Bearer $SHIELD_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "token": "<the verdict token>",
  "ip": "203.0.113.9",
  "ua": "Mozilla/5.0 ..."
}'
200
{
  "ok": true,
  "success": true,
  "score": 3,
  "verdict": "human",
  "action": "allow",
  "rules": [],
  "signals": {
    "hard": [],
    "soft": [],
    "st": []
  },
  "crawler": null,
  "issued_at": "2026-11-05T21:00:00Z",
  "age_s": 4
}

POST /assess

O cerere, sincron. challenge: servește pagina de verificare (429); block: 403. O decizie în observare răspunde allow, cu would. Cererea se numără la reguli exact ca o linie /ingest.

POST /assess
curl https://api.satelit.md/shield/v1/assess \
  -H "Authorization: Bearer $SHIELD_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "ip": "203.0.113.9",
  "ua": "Mozilla/5.0 ...",
  "method": "GET",
  "path": "/ro/catalog/",
  "host": "example.md",
  "kind": "html",
  "headers": {
    "sec-fetch-site": "none",
    "sec-ch-ua": "...",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\"",
    "accept-language": "ro-RO,ro;q=0.9",
    "referer": ""
  },
  "pass": "",
  "seen": true
}'
200
{
  "action": "allow",
  "rule": "",
  "mode": "",
  "would": "",
  "crawler": null,
  "key": "203.0.113.9",
  "until": null
}

POST /ingest

Loturi de cel mult 500 de linii, fără să aștepți răspunsul. k: html o pagină, api un apel JSON, asset un fișier. pass: 0 lipsă, 1 valabil, 2 prezent dar invalid. seen: cookie-ul __shs. g: 1 când răspunsul a fost pagina de verificare.

POST /ingest
curl https://api.satelit.md/shield/v1/ingest \
  -H "Authorization: Bearer $SHIELD_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "lines": [
    {
      "t": 1762369200000,
      "ip": "203.0.113.9",
      "ua": "Mozilla/5.0 ...",
      "m": "GET",
      "p": "/ro/catalog/",
      "s": 200,
      "k": "html",
      "h": {
        "sfs": "none",
        "chua": "...",
        "chm": "?0",
        "chp": "\"Windows\"",
        "al": "ro-RO",
        "ref": ""
      },
      "pass": 1,
      "seen": 1,
      "g": 0
    }
  ]
}'
200
{
  "ok": true,
  "n": 1,
  "decided": 0
}

GET /decisions?since=0

since=0, sau fără since, dă toată lista activă; cu cursorul primit, doar schimbările. a: b oprire (403), g verificare (429 fără un permis valabil), - ridicată. Deciziile în observare nu apar aici. Citește lista o dată la 15–30 de secunde și ține-o în memorie.

GET /decisions?since=0
curl "https://api.satelit.md/shield/v1/decisions?since=0" \
  -H "Authorization: Bearer $SHIELD_SECRET"
200
{
  "cursor": "1234",
  "full": true,
  "items": [
    {
      "key": "203.0.113.9",
      "a": "b",
      "rule": "automation",
      "until": "2026-11-06T21:00:00Z"
    },
    {
      "key": "2a01:4f8:1:2::",
      "a": "g",
      "rule": "no-proof",
      "until": "2026-11-06T21:00:00Z"
    },
    {
      "key": "198.51.100.4",
      "a": "-",
      "rule": "",
      "until": null
    }
  ]
}

GET /config

Setările site-ului: modurile, pragurile, calea-capcană, durata permisului, planul și consumul lunii.

GET /config
curl "https://api.satelit.md/shield/v1/config" \
  -H "Authorization: Bearer $SHIELD_SECRET"
200
{
  "site": "shp_XXXXXXXXXXXXXXXXXXXXXXXX",
  "name": "example.md",
  "modes": {
    "automation": "enforce",
    "no-proof": "shadow"
  },
  "thresholds": {},
  "trap": "/_sh/t/9f3k2",
  "overlay": true,
  "pass_life": 43200,
  "plan": "shield_pro",
  "quota": {
    "month": "2026-11",
    "used": 1234,
    "limit": 2500000
  }
}

POST /trust

O adresă protejată pentru un număr de zile: regulile dure arată doar verificarea. Pentru un membru care plătește sau pentru un birou.

POST /trust
curl https://api.satelit.md/shield/v1/trust \
  -H "Authorization: Bearer $SHIELD_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "ip": "203.0.113.9",
  "days": 30
}'
200
{
  "ok": true,
  "key": "203.0.113.9",
  "until": "2026-12-05T21:00:00+00:00"
}

GET /events?limit=50 · GET /stats?days=7

Aceleași rânduri ca în panou: evenimentele, cu filtre după regulă și acțiune, și cifrele pe zile.

GET /events?limit=50
curl "https://api.satelit.md/shield/v1/events?limit=50" \
  -H "Authorization: Bearer $SHIELD_SECRET"
200
{
  "items": [
    {
      "id": 81,
      "at": "2026-11-05T21:04:00Z",
      "key": "198.51.100.7",
      "rule": "automation",
      "action": "ban",
      "mode": "enforce",
      "ua": "Mozilla/5.0 ... HeadlessChrome/141.0.0.0 ...",
      "evidence": {
        "hard": [
          "wd"
        ]
      }
    }
  ]
}

Verifică tokenul la formulare

La un vot, un comentariu sau o înregistrare, pagina cere un token cu SatelitShield.token() și îl trimite cu formularul. Serverul tău îl verifică o singură dată, în 300 de secunde.

curl https://api.satelit.md/shield/v1/verify \
  -H "Authorization: Bearer $SHIELD_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "token": "<the token from the form>",
    "ip": "203.0.113.9"
  }'
// Node 18+: the token came with the form, ip is the visitor's address
async function fromPerson(token, ip) {
  const res = await fetch("https://api.satelit.md/shield/v1/verify", {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.SHIELD_SECRET}`, "Content-Type": "application/json" },
    body: JSON.stringify({ token, ip }),
  });
  const v = await res.json();
  return v.success === true && v.action !== "block";
}
import json, os, urllib.request

def from_person(token, ip):
    req = urllib.request.Request(
        "https://api.satelit.md/shield/v1/verify",
        data=json.dumps({"token": token, "ip": ip}).encode(),
        headers={"Authorization": f"Bearer {os.environ['SHIELD_SECRET']}", "Content-Type": "application/json"},
    )
    with urllib.request.urlopen(req, timeout=5) as res:
        v = json.load(res)
    return v.get("success") is True and v.get("action") != "block"
<?php
function from_person(string $token, string $ip): bool {
    $ch = curl_init("https://api.satelit.md/shield/v1/verify");
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_TIMEOUT => 5,
        CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("SHIELD_SECRET"), "Content-Type: application/json"],
        CURLOPT_POSTFIELDS => json_encode(["token" => $token, "ip" => $ip]),
    ]);
    $v = json_decode(curl_exec($ch), true);
    curl_close($ch);
    return ($v["success"] ?? false) === true && ($v["action"] ?? "") !== "block";
}

Un middleware în Node

Deciziile în memorie, cererile la /ingest în loturi, permisul verificat local. Rulează așa cum este, cu SHIELD_SECRET și SHIELD_SITE în mediu.

Opțional, pentru tot site-ul. Un middleware ține deciziile în memorie, le citește din /decisions o dată la 15–30 de secunde și trimite cererile în loturi la /ingest. Nicio cerere a unui vizitator nu așteaptă rețeaua.

shield-middleware.mjs
// Satelit Shield in a Node server: Express or any (req, res, next) stack. Node 18+, no packages.
// The decisions stay in memory and are read again every 20 s, so a visitor's request never waits for the network.
// Every request is sent to /ingest in batches. /_sh/ (the sensor) is served by the proxy in front, step 1.
import { clientKey, passValid } from "./shield-pass.mjs";

const API = process.env.SHIELD_API || "https://api.satelit.md/shield/v1";
const SECRET = process.env.SHIELD_SECRET;   // shs_..., never in a page
const SITE = process.env.SHIELD_SITE;       // shp_..., the public site key
const HEADERS = { Authorization: `Bearer ${SECRET}`, "Content-Type": "application/json" };
const decisions = new Map();                // client key -> { a: "b" | "g", rule, until }
const lines = [];
let cursor = "0";

export async function poll() {
  const res = await fetch(`${API}/decisions?since=${cursor}`, { headers: HEADERS });
  if (!res.ok) return;
  const body = await res.json();
  if (body.full) decisions.clear();
  for (const d of body.items) {
    if (d.a === "-") decisions.delete(d.key);
    else decisions.set(d.key, d);
  }
  cursor = body.cursor;
}

export async function flush() {
  while (lines.length) {
    const batch = lines.splice(0, 500);
    await fetch(`${API}/ingest`, { method: "POST", headers: HEADERS, body: JSON.stringify({ lines: batch }) }).catch(() => {});
  }
}

export function start() {
  const quiet = (job) => () => job().catch(() => {});
  quiet(poll)();
  setInterval(quiet(poll), 20_000).unref();
  setInterval(quiet(flush), 5_000).unref();
}

const cookie = (req, name) => new RegExp(`(?:^|;\\s*)${name}=([^;]*)`).exec(req.headers.cookie ?? "")?.[1] ?? "";
const page = (mode, text) => `<!doctype html><html data-shield="${mode}"><head><meta charset="utf-8">`
  + `<meta content="noindex" name="robots"><meta name="viewport" content="width=device-width">`
  + `<script src="/_sh/sensor.js" data-site="${SITE}" data-base="/_sh" async></script></head><body><p>${text}</p></body></html>`;

export function shield(req, res, next) {
  const ip = req.ip ?? req.socket.remoteAddress;   // behind a proxy: Express's "trust proxy" gives the visitor's address
  const ua = req.headers["user-agent"] ?? "";
  const path = (req.originalUrl ?? req.url).split("?")[0];
  const shp = cookie(req, "__shp");
  const pass = !shp ? 0 : passValid(shp, SECRET, ip, ua) ? 1 : 2;
  const d = decisions.get(clientKey(ip));
  const on = d && (!d.until || Date.parse(d.until) > Date.now()) ? d.a : "";
  // a ban is a 403; a check is a 429 unless the browser holds a valid pass (a pass never opens a ban)
  const gate = on === "b" ? 403 : on === "g" && pass !== 1 ? 429 : 0;
  res.on("finish", () => {
    const type = String(res.getHeader("content-type") ?? "");
    const kind = /\.(css|js|mjs|png|jpe?g|gif|svg|webp|avif|ico|woff2?)$/i.test(path) ? "asset" : /json/.test(type) ? "api" : "html";
    const h = (name) => req.headers[name] ?? "";
    lines.push({
      t: Date.now(), ip, ua, m: req.method, p: path, s: res.statusCode, k: kind,
      h: { sfs: h("sec-fetch-site"), chua: h("sec-ch-ua"), chm: h("sec-ch-ua-mobile"), chp: h("sec-ch-ua-platform"), al: h("accept-language"), ref: h("referer") },
      pass, seen: cookie(req, "__shs") === "1" ? 1 : 0, g: gate === 429 ? 1 : 0,
    });
  });
  if (!gate) return next();
  res.statusCode = gate;
  res.setHeader("Content-Type", "text/html; charset=utf-8");
  res.setHeader("Cache-Control", "no-store");
  res.end(gate === 429 ? page("check", "Checking your browser.") : page("ban", "Access blocked."));
}

Erori

Un apel greșit răspunde cu error.code și error.message.

CodCând
unauthorizedSecretul lipsește sau este greșit.
forbidden_originPagina nu este pe un domeniu al site-ului (sau un subdomeniu).
invalidCererea nu are forma din această pagină.
quotaVerificările lunii s-au terminat. Senzorul nu strică pagina: răspunde ca și cum nu ar fi nimic de făcut.
busyShield este ocupat. Încearcă din nou peste câteva secunde.
not_foundSite-ul sau resursa nu există.
401
{
  "error": {
    "code": "unauthorized",
    "message": "The secret is missing or wrong"
  }
}

Regulile

Fiecare regulă are modul ei: off, shadow sau enforce.

Regulile dure opresc o adresă neprotejată. Cele slabe arată doar verificarea. O regulă care trece de 50 de opriri pe oră, sau un site care trece de 200, revine singură la observare, iar tu primești un eveniment.

  • automation durăsenzor

    WebDriver, ChromeDriver, Selenium, PhantomJS, Nightmare, Playwright, Puppeteer, Cypress, TestCafe, HeadlessChrome.

  • stealth durăsenzor

    Automatizare peticită: Function.toString înlocuit, fereastră din iframe detașat, webdriver redefinit, Chromium deghizat în Chrome, un worker care spune HeadlessChrome.

  • antidetect dură sau slabăsenzor

    Amprentă falsificată: motor JS mai vechi decât browserul declarat, zgomot pe canvas, ecran diferit de CSS, fus orar, limbă, fonturi de sistem lipsă, worker sau Client Hints în dezacord.

  • fake-crawler durăambele

    Un nume de crawler infirmat de două surse independente: lista IP oficială și DNS-ul invers.

  • robots durăcereri

    Un bot declarat care cere căi interzise grupului său din robots.txt.

  • trap durăcereri

    Calea-capcană ascunsă a site-ului, interzisă în robots.txt.

  • challenge-ignored durăcereri

    Pagina de verificare servită de 6 sau mai multe ori aceleiași adrese, fără răspuns.

  • browser-soft slabăsenzor

    Două sau mai multe semne slabe: fără pluginuri pe Chrome desktop, fără window.chrome, limbi goale, WebGL software, protocolul DevTools.

  • no-proof slabăcereri

    12 sau mai multe pagini în 10 minute, fără raport al senzorului și fără cookie-ul __shs.

  • rate slabăcereri

    60 sau mai multe pagini pe minut.

  • walk slabăcereri

    40 sau mai multe pagini diferite în 10 minute.

  • stale-browser slabăcereri

    Chrome desktop cu 8 sau mai multe versiuni în urmă, fără permis și fără __shs.

  • ua-claim slabăcereri

    Chrome 101+ cu numărul complet de build (Chrome real scrie N.0.0.0) sau fără Sec-Fetch-Site pe Chrome 80+.

  • client-hints slabăcereri

    Antetele Sec-CH-UA contrazic User-Agent-ul: mobil, platformă, versiune, sau lipsesc pe Chrome 90+.

  • datacenter slabăambele

    Un User-Agent de browser dintr-o rețea de hosting sau cloud (ASN), fără permis.

Nu sunt judecați niciodată
Crawlerele verificate și lista ta de permise.
Doar verificare, niciodată oprire
Ieșirile Tor, adresele comune (3 sau mai multe browsere reale pe aceeași adresă în 24 de ore) și adresele în care ai încredere.

Ce păstrează Shield

  • Doar ID-uri de verificări. Senzorul trimite ID-urile verificărilor, numărul de interacțiuni (fără poziții sau taste) și prima limbă a browserului. Niciun hash de amprentă.
  • Cookie-uri doar pe domeniul tău. __shp, permisul după o verificare, și __shs, semnul că browserul a rulat senzorul. Satelit nu pune niciun cookie al său.
  • Păstrare scurtă. Cheia clientului (adresa sau rețeaua /64), User-Agent-ul, regula și dovada ei: 30 de zile. Contoarele pe oră: 90 de zile.
  • Secretul rămâne pe server. Cheia site-ului e publică. Secretul îl vezi o singură dată, iar Satelit păstrează doar hash-ul lui.

Despre Satelit Shield