<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Esli's Blog]]></title><description><![CDATA[Pagina pessoal do Esli Silva sobre Linux, SRE, DevOps, GNU, OpenSource, Tech, CAC, CR, Krav Maga e diversos outros temas, uma Mixórdia.]]></description><link>https://esli.blog.br</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1630032598779/RXgrEHnmO.png</url><title>Esli&apos;s Blog</title><link>https://esli.blog.br</link></image><generator>RSS for Node</generator><lastBuildDate>Wed, 22 Apr 2026 17:05:03 GMT</lastBuildDate><atom:link href="https://esli.blog.br/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Beyond GPG: Hardware-Backed File Encryption with age and YubiKey]]></title><description><![CDATA[1. Introduction: The Problem with GPG
GPG has been the de facto standard for file encryption for decades, but its age shows. The OpenPGP specification (RFC 4880) carries decades of backward compatibil]]></description><link>https://esli.blog.br/beyond-gpg-hardware-backed-file-encryption-with-age-and-yubikey</link><guid isPermaLink="true">https://esli.blog.br/beyond-gpg-hardware-backed-file-encryption-with-age-and-yubikey</guid><category><![CDATA[encryption]]></category><category><![CDATA[yubikey]]></category><category><![CDATA[yubikeys]]></category><category><![CDATA[yubico]]></category><category><![CDATA[Security]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Sun, 12 Apr 2026 02:02:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/fc0c5fd4-6104-4c3d-95f7-5d818c2c2a7b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>1. Introduction: The Problem with GPG</h2>
<p>GPG has been the de facto standard for file encryption for decades, but its age shows. The OpenPGP specification (RFC 4880) carries decades of backward compatibility baggage: configurable cipher suites that invite downgrade attacks, a web-of-trust model that almost nobody uses correctly, a keyring/keyserver architecture that leaks metadata, and a UX so hostile that even security professionals routinely misconfigure it. The attack surface is enormous — not because the cryptography is weak, but because the <em>decision space</em> presented to the user is.</p>
<p>OpenSSL's <code>enc</code> command is another common choice, but it's even worse from a usability standpoint: no native public-key encryption, no authenticated encryption by default (CBC mode without HMAC), and easy-to-forget flags that silently produce insecure output.</p>
<p><a href="https://github.com/FiloSottile/age">age</a> was created by Filippo Valsorda (former Go cryptography lead at Google) to solve exactly this problem: provide a file encryption tool that is <strong>secure by default</strong>, with no configuration knobs to turn wrong, explicit key management, and UNIX-style composability. When combined with <a href="https://github.com/str4d/age-plugin-yubikey">age-plugin-yubikey</a>, it delivers hardware-backed key protection with a fraction of GPG+smartcard complexity.</p>
<h2>2. What is age</h2>
<p><code>age</code> (pronounced "ah-geh", from the Italian word) is a file encryption tool, file format, and library. Its design philosophy can be summarized in four principles:</p>
<ul>
<li><p><strong>No configuration.</strong> No config files, no keyrings, no keyservers. Keys are explicit arguments.</p>
</li>
<li><p><strong>No algorithm negotiation.</strong> One cipher suite, chosen by the developers, not the user.</p>
</li>
<li><p><strong>Small explicit keys.</strong> Recipients are short strings (<code>age1...</code>) that fit in a chat message.</p>
</li>
<li><p><strong>UNIX composability.</strong> Reads from stdin, writes to stdout, pipes cleanly.</p>
</li>
</ul>
<p>The format specification lives at <a href="https://age-encryption.org/v1">age-encryption.org/v1</a> and has multiple interoperable implementations: the reference Go implementation (<a href="https://github.com/FiloSottile/age">filippo.io/age</a>), <code>rage</code> in Rust, <code>typage</code> in TypeScript, and others in Python, Java, Kotlin, and Swift. The plugin system (introduced in v1.1.0) enables custom recipient types — hardware tokens, cloud KMS, post-quantum hybrids — without touching the core format.</p>
<h2>3. Cryptographic Primitives</h2>
<p><code>age</code> uses a deliberately small, modern cryptographic suite with no user-selectable options:</p>
<table>
<thead>
<tr>
<th>Primitive</th>
<th>Algorithm</th>
<th>Purpose</th>
</tr>
</thead>
<tbody><tr>
<td>Key agreement</td>
<td><strong>X25519</strong> (Curve25519 ECDH)</td>
<td>Asymmetric key wrapping for <code>age1...</code> recipients</td>
</tr>
<tr>
<td>Symmetric encryption</td>
<td><strong>ChaCha20-Poly1305</strong></td>
<td>AEAD encryption of the file payload</td>
</tr>
<tr>
<td>Key derivation</td>
<td><strong>HKDF-SHA-256</strong></td>
<td>Deriving the header MAC key and stream key from the file key</td>
</tr>
<tr>
<td>Passphrase KDF</td>
<td><strong>scrypt</strong></td>
<td>Stretching passphrases into encryption keys</td>
</tr>
</tbody></table>
<h3>How it fits together</h3>
<ol>
<li><p>A random 16-byte <strong>file key</strong> is generated per encryption operation.</p>
</li>
<li><p>The file key is <strong>wrapped</strong> (encrypted) independently for each recipient — using X25519 ephemeral ECDH for public-key recipients, scrypt for passphrases, or a plugin-specific mechanism for hardware tokens.</p>
</li>
<li><p>Each wrapped copy becomes a <strong>stanza</strong> in the ASCII header.</p>
</li>
<li><p>HKDF-SHA-256 derives two keys from the file key: one for the <strong>header MAC</strong> (authenticating the header stanzas) and one for the <strong>payload stream key</strong>.</p>
</li>
<li><p>The payload is encrypted as a stream of <strong>64 KiB chunks</strong> using ChaCha20-Poly1305, where each chunk is independently authenticated.</p>
</li>
</ol>
<p>This design provides <strong>forward privacy</strong> (ephemeral ECDH keys mean a compromised long-term key cannot decrypt past ciphertexts) and <strong>multi-recipient support</strong> without re-encrypting the payload — only the 16-byte file key is wrapped once per recipient.</p>
<p>For post-quantum resistance, <code>age</code> now supports hybrid <strong>ML-KEM-768 + X25519</strong> keys (recipients starting with <code>age1pq1...</code>), though this is still experimental.</p>
<h2>4. Basic age Usage</h2>
<h3>Key generation</h3>
<pre><code class="language-bash"># Generate a new X25519 key pair
age-keygen -o key.txt
# Output:
# Public key: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# The file contains the secret key (AGE-SECRET-KEY-1...)
# The public key is printed to stderr
</code></pre>
<h3>Encryption and decryption</h3>
<pre><code class="language-bash"># Encrypt to a recipient's public key
age -r age1recipient... -o secret.txt.age secret.txt

# Encrypt to multiple recipients
age -r age1alice... -r age1bob... -o shared.age document.pdf

# Encrypt with a passphrase (interactive prompt)
age -p -o backup.tar.age backup.tar

# Decrypt with a key file
age -d -i key.txt -o secret.txt secret.txt.age

# Pipe-friendly usage
tar czf - ./project | age -r age1recipient... &gt; project.tar.gz.age
age -d -i key.txt &lt; project.tar.gz.age | tar xzf -
</code></pre>
<h3>SSH key compatibility</h3>
<pre><code class="language-bash"># Encrypt to an existing SSH public key
age -R ~/.ssh/id_ed25519.pub -o secret.age secret.txt

# Decrypt with the corresponding SSH private key
age -d -i ~/.ssh/id_ed25519 secret.age &gt; secret.txt
</code></pre>
<h2>5. YubiKey Integration</h2>
<p>This is where <code>age</code> genuinely outclasses GPG. Setting up GPG with a smartcard involves generating keys on the host, moving subkeys to card slots, managing trust databases, and configuring <code>gpg-agent</code>. With <code>age-plugin-yubikey</code>, the entire flow is: install the plugin, run one command, encrypt.</p>
<h3>How age-plugin-yubikey works</h3>
<p>The plugin uses the YubiKey's <strong>PIV (Personal Identity Verification) applet</strong> — the same applet used for smart card authentication in enterprise environments. Specifically:</p>
<ul>
<li><p>It generates an <strong>ECDSA P-256</strong> key pair directly on the YubiKey.</p>
</li>
<li><p>The private key <strong>never leaves the hardware</strong>.</p>
</li>
<li><p>The key is stored in one of the <strong>20 "retired" PIV slots</strong> (82–95), which avoids conflicts with standard PIV slots (9a, 9c, 9d, 9e) that may hold RSA keys for other purposes.</p>
</li>
<li><p>An <code>age</code> identity file is produced that contains the <strong>slot reference and YubiKey serial number</strong> — enough for the plugin to locate the key at decryption time, but not the key material itself.</p>
</li>
</ul>
<p>The plugin acts as a bridge: <code>age</code> clients discover it via the naming convention (<code>age-plugin-yubikey</code> in <code>$PATH</code>), delegate key operations to it, and the plugin communicates with the YubiKey via the PC/SC interface.</p>
<h3>HMAC-SHA1 Challenge-Response vs. PIV: Two Approaches Compared</h3>
<p>The <a href="https://github.com/Esl1h/yubikey-shell-toolkit">YubiKey Shell Toolkit</a> implements both approaches. Understanding the tradeoffs is important:</p>
<table>
<thead>
<tr>
<th>Aspect</th>
<th>HMAC-SHA1 (OTP Slot 2)</th>
<th>PIV + age</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Mechanism</strong></td>
<td>Challenge-response to derive an AES key via PBKDF2</td>
<td>ECDH key agreement using PIV-stored P-256 key</td>
</tr>
<tr>
<td><strong>Encryption</strong></td>
<td>AES-256-CBC via OpenSSL (+ PBKDF2, 600k iterations)</td>
<td>ChaCha20-Poly1305 via <code>age</code> (authenticated encryption)</td>
</tr>
<tr>
<td><strong>Artifacts</strong></td>
<td><code>.yk.enc</code> file + <code>.yk.challenge</code> file (both required)</td>
<td>Single <code>.age</code> file + identity file for decryption</td>
</tr>
<tr>
<td><strong>Multi-recipient</strong></td>
<td>Not natively supported</td>
<td>Native <code>age</code> feature — wrap file key per recipient</td>
</tr>
<tr>
<td><strong>Ecosystem</strong></td>
<td>Custom scripts, toolkit-specific</td>
<td>Standard <code>age</code> format, interoperable with all <code>age</code> clients</td>
</tr>
<tr>
<td><strong>PIN policy</strong></td>
<td>Touch only (configured at slot programming)</td>
<td>Configurable: <code>never</code>, <code>once</code>, <code>always</code> for both PIN and touch</td>
</tr>
<tr>
<td><strong>Authentication</strong></td>
<td>No AEAD — CBC without integrated MAC</td>
<td>AEAD (Poly1305) — tamper detection built in</td>
</tr>
</tbody></table>
<p><strong>The HMAC approach</strong> is simpler and works on YubiKeys without PIV support, but it relies on OpenSSL's <code>enc</code> command in CBC mode (not authenticated encryption) and requires managing an auxiliary <code>.yk.challenge</code> file. The challenge file alone is not sensitive — without the physical YubiKey to compute the HMAC response, it's useless — but losing it means losing the file.</p>
<p><strong>The PIV approach</strong> is strictly superior for most use cases: authenticated encryption, multi-recipient support, a standardized format, and configurable PIN/touch policies. Use HMAC only when PIV is unavailable (e.g., YubiKey NEO).</p>
<h4>HMAC approach (for reference)</h4>
<p>The <a href="https://github.com/Esl1h/yubikey-shell-toolkit/blob/main/yk-encrypt-file.sh"><code>yk-encrypt-file.sh</code></a> script demonstrates the HMAC flow:</p>
<pre><code class="language-bash">#!/usr/bin/env bash
set -euo pipefail

INPUT="\({1:?Usage: \)0 &lt;file&gt;}"
FILE="\((cd "\)(dirname "\(INPUT")" &amp;&amp; pwd)/\)(basename "$INPUT")"
SLOT=2

# Generate random challenge
CHALLENGE=$(openssl rand -hex 32)

# YubiKey computes HMAC — secret never leaves hardware
HMAC=\((ykman otp calculate 2 "\)CHALLENGE" 2&gt;/dev/null) || {
    echo "[!] YubiKey did not respond." &gt;&amp;2; exit 1
}

# Derive AES-256 key from challenge+HMAC
KEY=\((echo -n "\){CHALLENGE}${HMAC}" | openssl dgst -sha256 -binary | xxd -p -c 256)

# Encrypt with AES-256-CBC + PBKDF2
openssl enc -aes-256-cbc -pbkdf2 -iter 600000 \
    -k "\(KEY" -in "\)FILE" -out "${FILE}.yk.enc"

echo "\(CHALLENGE" &gt; "\){FILE}.yk.challenge"
</code></pre>
<h3>Installation and Setup</h3>
<h4>Prerequisites</h4>
<pre><code class="language-bash"># Debian/Ubuntu
sudo apt-get install pcscd age libpcsclite-dev

# Fedora
sudo dnf install pcsc-lite age pcsc-lite-devel

# Arch
sudo pacman -S pcsclite pcsc-tools yubikey-manager age

# Ensure pcscd is running
sudo systemctl enable --now pcscd
</code></pre>
<h4>Install age-plugin-yubikey</h4>
<pre><code class="language-bash"># Homebrew (macOS/Linux)
brew install age-plugin-yubikey

# Cargo (Rust 1.70+)
cargo install age-plugin-yubikey

# Arch Linux
pacman -S age-plugin-yubikey
</code></pre>
<p>Pre-built binaries for Windows, Linux, and macOS are available on the <a href="https://github.com/str4d/age-plugin-yubikey/releases">releases page</a>.</p>
<h4>Generate a YubiKey identity</h4>
<p><strong>Interactive mode</strong> (recommended for first-time setup):</p>
<pre><code class="language-bash">age-plugin-yubikey
</code></pre>
<p>This launches a text-based wizard that:</p>
<ol>
<li><p>Detects connected YubiKeys and lets you select one.</p>
</li>
<li><p>Shows available PIV slots and selects a free "retired" slot (e.g., slot 82).</p>
</li>
<li><p>Prompts you to name the identity.</p>
</li>
<li><p>Asks for <strong>PIN policy</strong> (<code>never</code>, <code>once</code>, <code>always</code>) and <strong>touch policy</strong> (<code>never</code>, <code>always</code>, <code>cached</code>).</p>
</li>
<li><p>If default PINs are detected, prompts you to change them.</p>
</li>
<li><p>If the default management key is detected, generates a random one and stores it in PIN-protected metadata.</p>
</li>
</ol>
<p><strong>Programmatic mode</strong>:</p>
<pre><code class="language-bash">age-plugin-yubikey --generate \
    --slot 1 \
    --name "backup-encryption" \
    --pin-policy once \
    --touch-policy always \
    &gt; ~/.config/yk-toolkit/age/yubikey-identity.txt
</code></pre>
<p>Extract the recipient (public key) for sharing:</p>
<pre><code class="language-bash"># List all age recipients from connected YubiKeys
age-plugin-yubikey --list

# Or extract from a specific slot
age-plugin-yubikey --identity --slot 1 2&gt;/dev/null \
    | grep "^# recipient:" | cut -d' ' -f3 \
    &gt; ~/.config/yk-toolkit/age/yubikey-recipient.txt
</code></pre>
<h3>Practical Examples</h3>
<h4>Single-recipient encryption with YubiKey</h4>
<p>The <a href="https://github.com/Esl1h/yubikey-shell-toolkit/blob/main/yk-age-encrypt.sh"><code>yk-age-encrypt.sh</code></a> script wraps <code>age</code> with sensible defaults:</p>
<pre><code class="language-bash"># Encrypt using the stored YubiKey recipient
./yk-age-encrypt.sh document.pdf
# → document.pdf.age

# Encrypt with an explicit recipient
./yk-age-encrypt.sh -r age1yubikey1qfmj3... -o secrets.age secrets.env

# Decrypt (requires physical YubiKey + PIN/touch)
./yk-age-decrypt.sh document.pdf.age
</code></pre>
<p>The script automatically resolves the recipient by checking (in order):</p>
<ol>
<li><p>The <code>-r</code> flag.</p>
</li>
<li><p><code>~/.config/yk-toolkit/age/yubikey-recipient.txt</code>.</p>
</li>
<li><p>Live query via <code>age-plugin-yubikey --list</code>.</p>
</li>
</ol>
<h4>Direct age commands (no wrapper)</h4>
<pre><code class="language-bash"># Encrypt
age -r age1yubikey1qfmj3... -o report.age report.xlsx

# Decrypt — the plugin handles YubiKey interaction transparently
age -d -i yubikey-identity.txt -o report.xlsx report.age
</code></pre>
<p>When the touch policy is set to <code>always</code>, the YubiKey's LED will blink during decryption — physical touch is required to authorize the cryptographic operation.</p>
<h2>6. Multi-Recipient Encryption</h2>
<p>This is where <code>age</code> + YubiKey truly shines for team workflows. Since <code>age</code> wraps the file key independently for each recipient, you can encrypt a single file to multiple YubiKeys, software keys, or a mix of both.</p>
<h3>Use cases</h3>
<ul>
<li><p><strong>Team access</strong>: Encrypt shared secrets to every team member's YubiKey.</p>
</li>
<li><p><strong>Redundancy</strong>: Encrypt to both a primary and backup YubiKey in case one is lost.</p>
</li>
<li><p><strong>Hybrid recovery</strong>: Encrypt to your YubiKey <em>and</em> a passphrase-protected software key stored in a safe.</p>
</li>
<li><p><strong>CI/CD pipelines</strong>: Encrypt to a hardware key for humans and a software key for automation.</p>
</li>
</ul>
<h3>Multi-recipient scripts</h3>
<p>The <a href="https://github.com/Esl1h/yubikey-shell-toolkit/blob/main/yk-age-encrypt-multikeys.sh"><code>yk-age-encrypt-multikeys.sh</code></a> script supports multiple recipients via <code>-r</code> flags or a recipients file:</p>
<pre><code class="language-bash"># Encrypt to multiple recipients via flags
./yk-age-encrypt-multikeys.sh \
    -r age1yubikey1qfmj3...   \
    -r age1yubikey1q2xk7...   \
    -r age1ql3z7hjy54pw...    \
    secrets.tar.gz

# Or maintain a recipients file
cat ~/.config/yk-toolkit/age/recipients.txt
# Primary YubiKey
age1yubikey1qfmj3...
# Backup YubiKey
age1yubikey1q2xk7...
# Software fallback key
age1ql3z7hjy54pw...

# Encrypt using the recipients file (auto-loaded)
./yk-age-encrypt-multikeys.sh secrets.tar.gz
</code></pre>
<p>The corresponding <a href="https://github.com/Esl1h/yubikey-shell-toolkit/blob/main/yk-age-decrypt-multikeys.sh"><code>yk-age-decrypt-multikeys.sh</code></a> tries multiple identity files:</p>
<pre><code class="language-bash"># Decrypt with multiple identity files
./yk-age-decrypt-multikeys.sh \
    -i ~/yubikey-primary-identity.txt \
    -i ~/yubikey-backup-identity.txt \
    secrets.tar.gz.age

# Or maintain an identities file
cat ~/.config/yk-toolkit/age/identities.txt
/home/user/.config/yk-toolkit/age/yubikey-identity.txt
/home/user/.config/yk-toolkit/age/backup-identity.txt

# Decrypt using the identities file (auto-loaded)
./yk-age-decrypt-multikeys.sh secrets.tar.gz.age
</code></pre>
<p><code>age</code> will try each identity until one succeeds — you only need <em>one</em> matching YubiKey inserted.</p>
<h3>Practical redundancy pattern</h3>
<pre><code class="language-bash"># Setup: generate identities on two YubiKeys
age-plugin-yubikey --generate --slot 1 --name "primary" \
    --pin-policy once --touch-policy always &gt; primary-identity.txt

# Swap YubiKeys
age-plugin-yubikey --generate --slot 1 --name "backup" \
    --pin-policy once --touch-policy always &gt; backup-identity.txt

# Also generate a software recovery key
age-keygen -o recovery-key.txt

# Collect all recipients
age-plugin-yubikey --list &gt; all-recipients.txt
grep "^# public" recovery-key.txt | cut -d: -f2 &gt;&gt; all-recipients.txt

# Encrypt backups to all three
tar czf - ~/documents | age -R all-recipients.txt -o backup.tar.gz.age
</code></pre>
<p>If the primary YubiKey is lost, decrypt with the backup or the software key. Then re-encrypt with a new set of recipients.</p>
<h2>7. Security Considerations and Best Practices</h2>
<h3>Hardware-backed key advantages</h3>
<ul>
<li><p><strong>Non-extractable private keys</strong>: The PIV applet does not allow exporting generated private keys. Even with physical access to the YubiKey and the PIN, the key material cannot be read.</p>
</li>
<li><p><strong>PIN brute-force protection</strong>: After 3 failed PIN attempts, the YubiKey locks. After 3 failed PUK attempts, the PIV applet is permanently locked (requires a full reset, destroying all keys).</p>
</li>
<li><p><strong>Touch confirmation</strong>: With <code>--touch-policy always</code>, every cryptographic operation requires physical contact — malware cannot silently decrypt files even if it has access to the identity file and the YubiKey is plugged in.</p>
</li>
</ul>
<h3>Best practices</h3>
<ol>
<li><p><strong>Change default PINs immediately.</strong> The default PIV PIN is <code>123456</code> and PUK is <code>12345678</code>. <code>age-plugin-yubikey</code> prompts for this, but verify.</p>
</li>
<li><p><strong>Use</strong> <code>--pin-policy once --touch-policy always</code> as a baseline. "Once" means the PIN is cached for the session (avoiding repeated prompts during batch decryption), while "always" touch prevents silent use.</p>
</li>
<li><p><strong>Always encrypt to at least two recipients</strong> — your primary YubiKey and a recovery mechanism (backup YubiKey or software key in secure storage).</p>
</li>
<li><p><strong>Protect identity files.</strong> While the identity file doesn't contain the private key, it tells <code>age</code> <em>which</em> YubiKey and slot to use. Treat it as sensitive metadata: <code>chmod 600</code>.</p>
</li>
<li><p><strong>Store software recovery keys offline</strong> — printed on paper, in a safe deposit box, or on an encrypted USB drive stored separately.</p>
</li>
<li><p><strong>Rotate keys when a YubiKey is lost.</strong> Re-encrypt all accessible data to a new recipient set that excludes the lost key.</p>
</li>
<li><p><strong>Pin caching caveat</strong>: On YubiKey 4 series, PIN cache preservation does not work due to how the serial number is obtained — the plugin performs a soft reset that clears the cache. YubiKey 5 series handles this correctly.</p>
</li>
</ol>
<h3>Threat model boundaries</h3>
<p><code>age</code> with YubiKey protects <strong>data at rest</strong>. It does not provide:</p>
<ul>
<li><p><strong>Signing or authentication</strong> (use SSH or FIDO2 for that).</p>
</li>
<li><p><strong>Forward secrecy for stored files</strong> — if a file was encrypted to a recipient, compromising that recipient's key allows decryption of that specific file. Forward privacy applies to the <em>encrypting</em> side (ephemeral ECDH), not the recipient's long-term key.</p>
</li>
<li><p><strong>Deniability</strong> — the header reveals the number of recipients (stanza count) and the recipient type (plugin name).</p>
</li>
</ul>
<h2>8. Ecosystem and Tooling</h2>
<h3>Core tools</h3>
<table>
<thead>
<tr>
<th>Tool</th>
<th>Language</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><a href="https://github.com/FiloSottile/age">age</a></td>
<td>Go</td>
<td>Reference implementation — CLI + library</td>
</tr>
<tr>
<td><a href="https://github.com/str4d/rage">rage</a></td>
<td>Rust</td>
<td>Alternative implementation, supports plugins</td>
</tr>
<tr>
<td><a href="https://github.com/str4d/age-plugin-yubikey">age-plugin-yubikey</a></td>
<td>Rust</td>
<td>YubiKey PIV integration</td>
</tr>
<tr>
<td><a href="https://github.com/FiloSottile/age">age-keygen</a></td>
<td>Go</td>
<td>Key generation (bundled with <code>age</code>)</td>
</tr>
</tbody></table>
<h3>Integration tools</h3>
<ul>
<li><p><a href="https://github.com/getsops/sops"><strong>SOPS</strong></a> — Mozilla's secret manager supports <code>age</code> as a backend. Combine with <code>age-plugin-yubikey</code> for hardware-backed secret management in GitOps workflows.</p>
</li>
<li><p><a href="https://github.com/Esl1h/yubikey-shell-toolkit"><strong>YubiKey Shell Toolkit</strong></a> — Bash scripts for both HMAC and age-based YubiKey encryption, including multi-recipient support, setup automation, and verification.</p>
</li>
<li><p><a href="https://github.com/FiloSottile/passage"><strong>passage</strong></a> — A password store (like <code>pass</code>) built on <code>age</code> instead of GPG.</p>
</li>
<li><p><a href="https://github.com/FiloSottile/awesome-age"><strong>awesome-age</strong></a> — Curated list of <code>age</code> ecosystem projects.</p>
</li>
</ul>
<h3>Relevant scripts from YubiKey Shell Toolkit</h3>
<table>
<thead>
<tr>
<th>Script</th>
<th>Purpose</th>
</tr>
</thead>
<tbody><tr>
<td><a href="https://github.com/Esl1h/yubikey-shell-toolkit/blob/main/yk-encrypt-file.sh"><code>yk-encrypt-file.sh</code></a></td>
<td>HMAC-based encryption (AES-256-CBC)</td>
</tr>
<tr>
<td><a href="https://github.com/Esl1h/yubikey-shell-toolkit/blob/main/yk-age-encrypt.sh"><code>yk-age-encrypt.sh</code></a></td>
<td>Single-recipient age + YubiKey PIV encryption</td>
</tr>
<tr>
<td><a href="https://github.com/Esl1h/yubikey-shell-toolkit/blob/main/yk-age-encrypt-multikeys.sh"><code>yk-age-encrypt-multikeys.sh</code></a></td>
<td>Multi-recipient age encryption</td>
</tr>
<tr>
<td><a href="https://github.com/Esl1h/yubikey-shell-toolkit/blob/main/yk-age-decrypt-multikeys.sh"><code>yk-age-decrypt-multikeys.sh</code></a></td>
<td>Multi-identity age decryption</td>
</tr>
</tbody></table>
<h2>9. Conclusion</h2>
<p><code>age</code> represents what encryption tooling should have been all along: a single correct cipher suite, explicit key management, no footguns. Adding YubiKey via <code>age-plugin-yubikey</code> elevates it from "good software encryption" to "hardware-rooted key protection" with remarkably little ceremony — <code>age-plugin-yubikey --generate</code>, then <code>age -r</code> as usual.</p>
<p>For teams, the multi-recipient model is the real differentiator. Encrypting shared secrets to every team member's YubiKey (plus a recovery key) is a one-liner, not a GPG keyring management odyssey. When someone leaves the team, re-encrypt to the updated recipient list. When a YubiKey is lost, the PIN lockout protects against brute force while you rotate.</p>
<p>The combination is particularly compelling for:</p>
<ul>
<li><p><strong>Encrypted backups</strong> — hardware-keyed, with software recovery fallback.</p>
</li>
<li><p><strong>Secret management in Git</strong> — via SOPS + age + YubiKey.</p>
</li>
<li><p><strong>Sensitive file exchange</strong> — share a short <code>age1yubikey1...</code> string, not a GPG key fingerprint ceremony.</p>
</li>
<li><p><strong>Compliance environments</strong> — hardware-backed key storage with touch confirmation satisfies many audit requirements.</p>
</li>
</ul>
<p>If you're still wrapping files with <code>gpg -c</code> or <code>openssl enc</code>, it's time to upgrade.</p>
<hr />
<h3>References</h3>
<ul>
<li><p>age — <a href="https://github.com/FiloSottile/age">github.com/FiloSottile/age</a></p>
</li>
<li><p>age format specification — <a href="https://age-encryption.org/v1">age-encryption.org/v1</a></p>
</li>
<li><p>age-plugin-yubikey — <a href="https://github.com/str4d/age-plugin-yubikey">github.com/str4d/age-plugin-yubikey</a></p>
</li>
<li><p>YubiKey Shell Toolkit — <a href="https://github.com/Esl1h/yubikey-shell-toolkit">github.com/Esl1h/yubikey-shell-toolkit</a></p>
</li>
<li><p>awesome-age ecosystem — <a href="https://github.com/FiloSottile/awesome-age">github.com/FiloSottile/awesome-age</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[age + yubikey]]></title><description><![CDATA[age é uma ferramenta de criptografia de arquivos. É o substituto moderno do gpg --encrypt.
Escrevi mais a respeito dele em https://esli.blog.br/age-criptografia-de-arquivos-simples-moderna-e-segura
Em]]></description><link>https://esli.blog.br/age-yubikey</link><guid isPermaLink="true">https://esli.blog.br/age-yubikey</guid><category><![CDATA[yubikey]]></category><category><![CDATA[yubikeys]]></category><category><![CDATA[yubico]]></category><category><![CDATA[Security]]></category><category><![CDATA[encryption]]></category><category><![CDATA[Cryptography]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Fri, 10 Apr 2026 13:20:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/4bc9f846-0c16-44b0-b3dc-92ad3e03e41f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>age é uma ferramenta de criptografia de arquivos. É o substituto moderno do gpg --encrypt.</p>
<p>Escrevi mais a respeito dele em <a href="https://esli.blog.br/age-criptografia-de-arquivos-simples-moderna-e-segura">https://esli.blog.br/age-criptografia-de-arquivos-simples-moderna-e-segura</a></p>
<p>Em resumo, o uso é o seguinte:</p>
<pre><code class="language-shell"># Encrypt
age -r age1ql3z7hjy8zmrj2kg5sfn9aqmcac8p -o file.enc file.txt

# Decrypt
age -d -i key.txt -o file.txt file.enc
</code></pre>
<h2>age + YubiKey PIV — como funciona</h2>
<p>O plugin age-plugin-yubikey usa o slot PIV da YubiKey (não o HMAC challenge-response) para encrypt/decrypt:</p>
<ul>
<li><p>Gera um key pair diretamente no YubiKey (chave privada nunca sai do hardware)</p>
</li>
<li><p>Exporta a identity (referência ao slot PIV) e o recipient (chave pública)</p>
</li>
<li><p>Encrypt usa a chave pública (não precisa da YubiKey)</p>
</li>
<li><p>Decrypt exige a YubiKey fisicamente presente + PIN + touch</p>
</li>
</ul>
<h3>Comparativo</h3>
<p>Criei dois .sh:</p>
<p>Um usando openssl com a chave Yubikey (HMAC): <a href="https://github.com/Esl1h/yubikey-shell-toolkit/blob/main/yk-encrypt-file.sh">https://github.com/Esl1h/yubikey-shell-toolkit/blob/main/yk-encrypt-file.sh</a></p>
<p>E o outro, usando o age com a chave Yubikey: <a href="https://github.com/Esl1h/yubikey-shell-toolkit/blob/main/yk-age-encrypt.sh">https://github.com/Esl1h/yubikey-shell-toolkit/blob/main/yk-age-encrypt.sh</a></p>
<table>
<thead>
<tr>
<th></th>
<th><a href="http://yk-encrypt.sh"><code>yk-encrypt.sh</code></a> (HMAC)</th>
<th><code>age</code> + YubiKey PIV</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Mecanismo</strong></td>
<td>Symmetric — HMAC-SHA1 → AES-256</td>
<td>Asymmetric — ECDH (P-256) → ChaCha20-Poly1305</td>
</tr>
<tr>
<td><strong>Encrypt sem YubiKey</strong></td>
<td>Precisa da chave física</td>
<td>Só precisa da chave pública (arquivo)</td>
</tr>
<tr>
<td><strong>Decrypt sem YubiKey</strong></td>
<td>Sempre será necessária a chave</td>
<td>Sempre será necessária a chave</td>
</tr>
<tr>
<td><strong>Chave privada</strong></td>
<td>Secret no slot OTP (extraível via reset)</td>
<td>Gerada no chip PIV (nunca exportável)</td>
</tr>
<tr>
<td><strong>Múltiplos recipients</strong></td>
<td>não</td>
<td>Pode cifrar para N chaves públicas</td>
</tr>
<tr>
<td><strong>Dependências</strong></td>
<td><code>openssl</code>, <code>ykman</code></td>
<td><code>age</code>, <code>age-plugin-yubikey</code></td>
</tr>
<tr>
<td><strong>Maturidade</strong></td>
<td>OpenSSL (battle-tested)</td>
<td>age (moderno, auditado, mas mais novo)</td>
</tr>
</tbody></table>
<h3>Caso de uso prático</h3>
<ul>
<li><p>Cifrar backups no servidor <strong>sem a YubiKey presente</strong> (só a chave pública)</p>
</li>
<li><p>Decifrar só na tua máquina com a YubiKey plugada</p>
</li>
<li><p>Compartilhar arquivos cifrados com múltiplas pessoas (cada uma com seu recipient)</p>
</li>
</ul>
<h2>Instalação do plugin</h2>
<pre><code class="language-shell">
# age-plugin-yubikey (Rust, via cargo ou release binário)
cargo install age-plugin-yubikey
</code></pre>
<h2>Encriptando com mais de uma chave Yubikey</h2>
<p>Segundo as recomendações, você deveria ter duas chaves Yubikey. Como encriptar permitindo o acesso ao arquivo posteriormente, com qualquer uma das duas?</p>
<p>Além disso, outra possibilidade com o age é encriptar um arquivo que possa ser desencriptado usando 5 ou 6 chaves específicas, trabalhando em equipe por exemplo.</p>
<p>Isto é nativo no age, a flag <code>-r</code> aceita múltiplos recipientes:</p>
<pre><code class="language-shell">age -r "\(RECIPIENT_1" -r "\)RECIPIENT_2" -r "$RECIPIENT_3" -o arquivo.age arquivo  
</code></pre>
<p>O <code>age</code> encripta uma chave de sessão efêmera para cada recipiente separadamente e qualquer uma das chaves privadas correspondentes consegue decriptar. É o mesmo modelo do PGP (<code>--recipient</code> múltiplo).</p>
<h3>Utilizando o script para múltiplas chaves:</h3>
<p><a href="https://github.com/Esl1h/yubikey-shell-toolkit/blob/main/yk-age-encrypt-multikeys.sh">https://github.com/Esl1h/yubikey-shell-toolkit/blob/main/yk-age-encrypt-multikeys.sh</a></p>
<p><a href="https://github.com/Esl1h/yubikey-shell-toolkit/blob/main/yk-age-decrypt-multikeys.sh">https://github.com/Esl1h/yubikey-shell-toolkit/blob/main/yk-age-decrypt-multikeys.sh</a></p>
<pre><code class="language-shell"># Encrypt para 3 YubiKeys
yk-age-encrypt-multikeys.sh -r age1yubikey1q... -r age1yubikey1q... -r age1... arquivo.txt


# Ou via recipients.txt (recomendado)
yk-age-encrypt-multikeys.sh arquivo.txt


# Decrypt com YubiKey específico
yk-age-decrypt-multikeys.sh -i ~/.config/yk-toolkit/age/yk2-identity.txt arquivo.txt.age
</code></pre>
<p>O age gera uma chave de sessão única e aleatória para o arquivo (usando ChaCha20-Poly1305).</p>
<p>Essa mesma chave de sessão é encriptada várias vezes: uma vez para a Chave A, uma para a Chave B, etc. Todas essas "versões" encriptadas da chave de sessão são guardadas no cabeçalho do arquivo .age.</p>
<p>Ao decriptar, o age testa as identidades que você possui. Se a sua YubiKey conseguir abrir qualquer um dos "cadeados" do cabeçalho, ela libera a chave de sessão e o arquivo é aberto.</p>
<p>Vantagens dessa abordagem:</p>
<ul>
<li><p>Redundância: Se você perder sua YubiKey principal, mas tiver configurado uma YubiKey de backup, você recupera seus dados.</p>
</li>
<li><p>Colaboração: Você pode encriptar um arquivo que tanto você quanto outros consigam abrir com suas respectivas chaves físicas.</p>
</li>
<li><p>Performance: A velocidade de encriptação e decriptação não muda quase nada, pois o arquivo em si é encriptado apenas uma vez; apenas o cabeçalho cresce alguns bytes para cada chave extra.</p>
</li>
</ul>
<h2>Conclusão</h2>
<p>O primeiro script (yk-encrypt.sh) usa o YubiKey como um gerador de senhas complexas que são transformadas em uma chave pelo OpenSSL; já o segundo (yk-age-encrypt.sh) através do age utiliza criptografia de chave pública (Piv), separando a chave pública da privada (guardada no hardware).</p>
<p>No age, a segurança é reforçada pelo uso do algoritmo ChaCha20-Poly1305, que além de esconder os dados, garante que ninguém altere sequer um bit do arquivo sem ser detectado, algo que o OpenSSL do primeiro script não faz automaticamente.</p>
<p>Para um atacante, o nível de risco de conseguir abrir seu arquivo sem possuir fisicamente o seu YubiKey é extremamente baixo, beirando o impossível com a tecnologia atual. No entanto, o script que usa o age é superior porque exige um PIN (senha numérica) para liberar o acesso ao hardware, adicionando uma camada extra de proteção: se alguém roubar seu YubiKey, ainda precisará da sua senha. Já no primeiro script (yk-encrypt.sh), a segurança depende totalmente de manter o arquivo de "challenge" guardado; se um atacante copiar seu arquivo encriptado e o arquivo de challenge, a única barreira restante é a posse física do YubiKey.</p>
<p>Portabilidade: O age é um binário único e estático. Você consegue decriptar esse arquivo em praticamente qualquer OS apenas instalando o age e conectando a chave.</p>
<p>Recuperação: Com PIV no YubiKey, é vital ter o PIN e o PUK anotados, pois se o PIN for bloqueado por excesso de tentativas, o acesso à chave privada é perdido permanentemente.</p>
<p>Identidade: A "chave pública" gerada pelo age (começando com age1...) pode ser compartilhada ou publicada sem medo — ela serve apenas para que as pessoas (ou seus scripts) possam encriptar arquivos para você. Inclusive, a minha está no perfil do meu GitHub.</p>
<p>Embora o uso de HMAC e OpenSSL seja uma solução funcional, o age foi projetado especificamente para ser simples, seguro e à prova de erros humanos. Ao usar o age-plugin-yubikey, você eleva o nível do seu workflow: elimina a necessidade de gerenciar arquivos de "challenge" extras, ganha proteção por PIN nativa do hardware e utiliza algoritmos de criptografia de última geração. Para quem busca proteger segredos em servidores, backups ou arquivos sensíveis no Linux, a combinação age + YubiKey é hoje um padrão-ouro de praticidade e segurança.</p>
]]></content:encoded></item><item><title><![CDATA[age: criptografia de arquivos simples, moderna e segura]]></title><description><![CDATA[Se você já usou GPG para cifrar um arquivo e sentiu que precisava de um diploma em criptografia aplicada só para lembrar quais flags usar, você não está sozinho. A experiência do GnuPG é tão sofrida q]]></description><link>https://esli.blog.br/age-criptografia-de-arquivos-simples-moderna-e-segura</link><guid isPermaLink="true">https://esli.blog.br/age-criptografia-de-arquivos-simples-moderna-e-segura</guid><category><![CDATA[Cryptography]]></category><category><![CDATA[Security]]></category><category><![CDATA[gpg]]></category><category><![CDATA[openssl]]></category><category><![CDATA[Rust]]></category><category><![CDATA[Go Language]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Thu, 09 Apr 2026 03:14:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/d2447394-d7f7-4397-9299-f93c9ec1880f.svg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Se você já usou GPG para cifrar um arquivo e sentiu que precisava de um diploma em criptografia aplicada só para lembrar quais flags usar, você não está sozinho. A experiência do GnuPG é tão sofrida que já virou quase um rito de passagem no mundo Linux: gerar chaves RSA de 4096 bits, lidar com keyrings, trust models, subkeys, revocation certificates, ...</p>
<p>Foi exatamente essa dor que motivou a criação do <strong>age</strong>.</p>
<h2>O que é o age</h2>
<p>O age (pronuncia-se com "g" duro, como o italiano "aghe" — e sim, sempre em minúsculas) é uma ferramenta de criptografia de arquivos criada por <a href="https://filippo.io/">Filippo Valsorda</a> e <a href="https://github.com/benjojo">Ben Cox</a>. Filippo não é um nome qualquer: ele foi o responsável pela equipe de criptografia do Go na Google e mantém atualmente a infraestrutura criptográfica do ecossistema Go.</p>
<p>O age é três coisas ao mesmo tempo:</p>
<ul>
<li><p><strong>Uma CLI</strong> (<code>age</code> e <code>age-keygen</code>) para cifrar e decifrar arquivos</p>
</li>
<li><p><strong>Um formato de arquivo</strong> com especificação aberta em <a href="https://age-encryption.org/v1">age-encryption.org/v1</a></p>
</li>
<li><p><strong>Uma biblioteca Go</strong> (<code>filippo.io/age</code>) para integração em aplicações</p>
</li>
</ul>
<p>A filosofia de design é simples: chaves pequenas e explícitas, zero opções de configuração, composabilidade no estilo UNIX. Não escolhe algoritmo, não configura nada, só cifra e decifra. Ponto.</p>
<h2>Por que o age existe</h2>
<p>O Filippo resumiu a motivação de forma direta: o age foi criado para substituir os casos de uso em que as pessoas usavam <code>gpg -c</code> (criptografia simétrica com passphrase) e <code>gpg -e</code> (criptografia com chave pública). A premissa é que, quando alguém chega no age, já sabe qual problema quer resolver — e quer uma ferramenta que poupe a dor de lidar com opções criptográficas legadas que ninguém deveria precisar entender.</p>
<p>O GPG/PGP carrega décadas de bagagem: algoritmos deprecados, negociação de parâmetros criptográficos (tamanho de chave, tipo de cifra, rounds), keyrings complexos, web of trust, e uma UX que parece ter sido projetada por um comitê em 1998, e na verdade, foi! O age joga tudo isso fora e começa do zero, com primitivas modernas e sem concessões retrocompatíveis.</p>
<p>Uma decisão deliberada e controversa: <strong>o age não suporta assinaturas digitais</strong>. A justificativa é que signing adiciona uma dimensão inteira de complexidade na UX, no gerenciamento de chaves e no design criptográfico de um formato streamable. O age cuida de integridade e confidencialidade, não de autenticação de remetente. Se você precisa de assinaturas, use <a href="https://jedisct1.github.io/minisign/">minisign</a> ou <a href="https://www.sigstore.dev/">sigstore</a> ferramentas especializadas para isso.</p>
<h2>Como funciona por baixo</h2>
<p>A criptografia do age é construída sobre primitivas bem estabelecidas:</p>
<p><strong>Cifra de payload:</strong> ChaCha20-Poly1305 — a mesma AEAD usada no WireGuard, TLS 1.3 e SSH. Em hardware sem AES-NI (como muitos ARM), ChaCha20 tende a ser mais rápido que AES-GCM. O payload é dividido em chunks de 64 KiB, cada um cifrado individualmente usando um esquema STREAM (variante do que é usado no Tink e Miscreant), o que permite cifrar e decifrar de forma streaming sem carregar o arquivo inteiro em memória.</p>
<p><strong>Troca de chaves (X25519):</strong> curva elíptica Curve25519 via Diffie-Hellman. As chaves públicas começam com <code>age1...</code> e são codificadas em Bech32 — curtas o suficiente para colar numa mensagem ou num arquivo de configuração. Uma chave pública age tem ~62 caracteres. Compare com uma chave pública RSA-4096 do GPG.</p>
<p><strong>Derivação de chaves:</strong> HKDF-SHA-256 é usada para derivar as chaves de wrap e payload a partir do segredo compartilhado e da file key.</p>
<p><strong>Passphrase (modo simétrico):</strong> scrypt para derivação, com work factor configurado automaticamente.</p>
<p><strong>Pós-quântico (v1.3.0+):</strong> suporte nativo a recipients híbridos ML-KEM-768 + X25519 (baseado em HPKE). Chaves começam com <code>age1pq1...</code>. Isso protege contra ataques de computadores quânticos futuros no modelo "harvest now, decrypt later".</p>
<p>O formato é estritamente definido: não há negociação de algoritmos, não há opções de configuração criptográfica. Uma cifra, uma curva, um KDF. Ponto. Isso elimina a classe inteira de vulnerabilidades que surgem de downgrade attacks e de escolhas ruins de parâmetros.</p>
<h2>Uso prático</h2>
<h3>Geração de chaves</h3>
<pre><code class="language-bash"># Chave X25519 padrão
age-keygen -o key.txt
# Public key: age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p

# Chave pós-quântica
age-keygen -pq -o key-pq.txt
</code></pre>
<h3>Cifrar e decifrar</h3>
<pre><code class="language-bash"># Cifrar com chave pública
age -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p secrets.tar.gz &gt; secrets.tar.gz.age

# Cifrar com passphrase
age -p secrets.txt &gt; secrets.txt.age

# Decifrar
age -d -i key.txt secrets.tar.gz.age &gt; secrets.tar.gz
</code></pre>
<h3>Composabilidade UNIX</h3>
<pre><code class="language-bash"># Cifrar um backup e enviar via SSH
tar czf - ~/docs | age -r age1... | ssh server "cat &gt; backup.tar.gz.age"

# Cifrar para múltiplos recipients
age -r age1alice... -r age1bob... arquivo.txt &gt; arquivo.txt.age

# Cifrar para as chaves SSH públicas de alguém no GitHub
curl https://github.com/usuario.keys | age -R - arquivo.txt &gt; arquivo.txt.age
</code></pre>
<h3>Suporte a chaves SSH</h3>
<p>O age aceita cifrar diretamente para chaves <code>ssh-ed25519</code> e <code>ssh-rsa</code>:</p>
<pre><code class="language-bash">age -R ~/.ssh/id_ed25519.pub arquivo.txt &gt; arquivo.txt.age
age -d -i ~/.ssh/id_ed25519 arquivo.txt.age &gt; arquivo.txt
</code></pre>
<p>Útil como atalho, mas as chaves SSH não são ideais para criptografia de longo prazo, por serem tipicamente revogáveis e pensadas para autenticação, não para cifrar dados que vão ficar armazenados por anos.</p>
<h3>Inspecionar arquivos cifrados</h3>
<p>Desde a v1.3.0, o <code>age-inspect</code> mostra metadados sem decifrar:</p>
<pre><code class="language-bash">age-inspect secrets.age
# secrets.age is an age file, version "age-encryption.org/v1".
# This file is encrypted to the following recipient types:
#   - "mlkem768x25519"
# This file uses post-quantum encryption.
</code></pre>
<h2>Instalação</h2>
<p>O age está empacotado em praticamente toda distro relevante:</p>
<pre><code class="language-bash"># Arch
pacman -S age

# Fedora
dnf install age

# Debian 12+ / Ubuntu 22.04+
apt install age

# macOS
brew install age

# Windows
winget install --id FiloSottile.age

# Via Go
go install filippo.io/age/cmd/...@latest
</code></pre>
<h2>age vs. GPG vs. OpenSSL vs. o resto</h2>
<p>Vamos ao que interessa: como o age se compara com as alternativas.</p>
<h3>GPG/PGP</h3>
<p>O elefante na sala. O GPG é o canivete suíço da criptografia — faz tudo, e faz tudo de forma dolorosamente complicada. Chaves enormes, keyrings frágeis, trust models que ninguém entende, algoritmos legados habilitados por padrão, UX hostil. O age resolve especificamente o caso de uso de criptografia de arquivos, descartando tudo que não é essencial.</p>
<p>O que o GPG ainda faz e o age não: assinaturas digitais, web of trust, integração nativa com clientes de e-mail, gerenciamento de identidades complexas. Se você precisa assinar commits (embora SSH também faça isso agora), assinar pacotes .deb ou manter uma identidade PGP para comunicação, o GPG ainda tem seu lugar.</p>
<p>O age foi projetado explicitamente para substituir <code>gpg -c</code> e <code>gpg -e</code>, não o GPG inteiro.</p>
<h3>OpenSSL</h3>
<p>O OpenSSL é uma biblioteca, não uma ferramenta de usuário final. Sim, você <em>pode</em> cifrar arquivos com <code>openssl enc</code>, mas está operando numa abstração muito baixa: precisa escolher o algoritmo, o modo de operação, lidar com IVs, derivação de chave, e o formato de saída não é padronizado. Um erro sutil e você compromete toda a segurança. O age abstrai tudo isso de forma segura por padrão.</p>
<h3>minisign / signify</h3>
<p>Ferramentas especializadas em assinaturas digitais. Não fazem criptografia. Complementam o age — use age para cifrar, minisign para assinar.</p>
<h3>Vault / SOPS / Sealed Secrets</h3>
<p>São ferramentas de gerenciamento de segredos, não de criptografia de arquivos de uso geral. Mas é aqui que o age brilha no ecossistema DevOps: o <strong>Mozilla SOPS</strong> suporta age como backend de criptografia, substituindo GPG com uma experiência infinitamente mais simples. O Flux CD recomenda explicitamente o uso de age em vez de PGP para gerenciar secrets no Kubernetes. O chezmoi (gerenciador de dotfiles) também tem suporte nativo.</p>
<h3>rage (Rust)</h3>
<p>O <a href="https://github.com/str4d/rage">rage</a> é uma implementação alternativa em Rust, totalmente interoperável com o age. Mesmo formato, mesmas chaves. Se você prefere binários Rust ou precisa integrar com o ecossistema Rust, é uma opção de primeira classe.</p>
<h3>Typage (TypeScript)</h3>
<p>O <a href="https://github.com/FiloSottile/typage">typage</a> é a implementação TypeScript oficial, mantida pelo próprio Filippo. Funciona no browser, Node.js, Deno e Bun. Suporta até WebAuthn/passkeys para criptografia via hardware.</p>
<h2>Ecossistema e adoção</h2>
<p>O age não é um projeto experimental de fim de semana. É um projeto maduro com adoção real:</p>
<ul>
<li><p><strong>21.6k+ stars no GitHub</strong>, 629 forks, 18 releases (v1.3.1 é a mais recente, de dezembro de 2025)</p>
</li>
<li><p><strong>Especificação formal</strong> mantida no <a href="https://github.com/C2SP/C2SP/blob/main/age.md">C2SP</a> com vetores de teste padronizados (CCTV)</p>
</li>
<li><p><strong>Implementações em múltiplas linguagens:</strong> Go (referência), Rust (rage), TypeScript (typage), Java (Jagged), Kotlin (kage), Swift (AgeKit)</p>
</li>
<li><p><strong>Integração com ferramentas de infraestrutura:</strong> SOPS, Flux CD, chezmoi, gopass, Logseq, Apache NiFi</p>
</li>
<li><p><strong>Plugins para hardware:</strong> age-plugin-yubikey, age-plugin-tpm, age-plugin-se (Secure Enclave)</p>
</li>
<li><p><strong>Empacotado em todas as distros Linux relevantes</strong>, macOS (Homebrew/MacPorts), Windows (winget/Chocolatey/Scoop), FreeBSD, OpenBSD</p>
</li>
<li><p><strong>Licença BSD-3-Clause</strong></p>
</li>
</ul>
<p>A lista completa de projetos do ecossistema está em <a href="https://github.com/FiloSottile/awesome-age">awesome-age</a>.</p>
<p>O estado de maturidade: o age atingiu a v1.0 em 2021, tem uma especificação formal estável, múltiplas implementações interoperáveis, suporte pós-quântico nativo desde v1.3.0, e é mantido ativamente por um dos criptógrafos mais respeitados do ecossistema open-source. É seguro tratá-lo como produção.</p>
<h2>O que o age não faz (e não pretende fazer)</h2>
<ul>
<li><p><strong>Assinaturas digitais</strong> — use minisign, sigstore, ou SSH signing</p>
</li>
<li><p><strong>Gerenciamento de identidades / web of trust</strong> — não existe um "keyring age"</p>
</li>
<li><p><strong>Criptografia de e-mail</strong> — não é o caso de uso; use PGP/GPG ou Signal</p>
</li>
<li><p><strong>Criptografia de disco</strong> — use LUKS/dm-crypt</p>
</li>
<li><p><strong>Comunicação em tempo real</strong> — use Noise framework, Signal, WireGuard</p>
</li>
</ul>
<p>O age é cirúrgico no escopo: criptografia de arquivos. Faz uma coisa e faz bem. A filosofia UNIX, como deveria ser.</p>
<h2>Exemplo prático: backup cifrado com age</h2>
<p>Um script mínimo para backup cifrado:</p>
<pre><code class="language-bash">#!/usr/bin/env bash
set -euo pipefail

RECIPIENT="age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p"
BACKUP_DIR="/backup"
SOURCE="$HOME/documentos"
DATE=$(date +%Y%m%d-%H%M%S)
DEST="\({BACKUP_DIR}/backup-\){DATE}.tar.zst.age"

tar cf - "$SOURCE" \
  | zstd -T0 --long -19 \
  | age -r "$RECIPIENT" \
  &gt; "$DEST"

echo "Backup cifrado: \(DEST (\)(du -h "$DEST" | cut -f1))"
</code></pre>
<p>Para restaurar:</p>
<pre><code class="language-bash">age -d -i ~/key.txt backup-20260405-120000.tar.zst.age | zstd -d | tar xf -
</code></pre>
<p>Composabilidade UNIX. Sem mágica, sem configuração, sem surpresas.</p>
<h2>Considerações finais</h2>
<p>O age é a resposta para quem quer cifrar arquivos sem precisar entender a história inteira da criptografia assimétrica desde 1991. Primitivas modernas, design minimalista, composabilidade UNIX, e um autor que sabe o que está fazendo.</p>
<p>Se você usa GPG apenas para cifrar arquivos (e sejamos honestos, esse é o caso de 90% das pessoas), o age é uma substituição direta e superior. Se você precisa do ecossistema completo do PGP (assinaturas, web of trust, integração com e-mail), o GPG continua sendo necessário — mas provavelmente menos do que você imagina.</p>
<p>Instale, gere uma chave, cifre algo. A experiência fala por si.</p>
<h2>Links e referências</h2>
<ul>
<li><p><strong>Repositório principal:</strong> <a href="https://github.com/FiloSottile/age">github.com/FiloSottile/age</a></p>
</li>
<li><p><strong>Especificação do formato:</strong> <a href="https://age-encryption.org/v1">age-encryption.org/v1</a></p>
</li>
<li><p><strong>Especificação formal (C2SP):</strong> <a href="https://github.com/C2SP/C2SP/blob/main/age.md">github.com/C2SP/C2SP/blob/main/age.md</a></p>
</li>
<li><p><strong>Man page:</strong> <a href="https://filippo.io/age/age.1">filippo.io/age/age.1</a></p>
</li>
<li><p><strong>rage (Rust):</strong> <a href="https://github.com/str4d/rage">github.com/str4d/rage</a></p>
</li>
<li><p><strong>Typage (TypeScript):</strong> <a href="https://github.com/FiloSottile/typage">github.com/FiloSottile/typage</a></p>
</li>
<li><p><strong>Jagged (Java):</strong> <a href="https://github.com/exceptionfactory/jagged">github.com/exceptionfactory/jagged</a></p>
</li>
<li><p><strong>age-plugin-yubikey:</strong> <a href="https://github.com/str4d/age-plugin-yubikey">github.com/str4d/age-plugin-yubikey</a></p>
</li>
<li><p><strong>awesome-age (ecossistema):</strong> <a href="https://github.com/FiloSottile/awesome-age">github.com/FiloSottile/awesome-age</a></p>
</li>
<li><p><strong>Blog do Filippo sobre autenticação no age:</strong> <a href="https://words.filippo.io/age-authentication/">words.filippo.io/age-authentication</a></p>
</li>
<li><p><strong>SOPS (Mozilla):</strong> <a href="https://github.com/getsops/sops">github.com/getsops/sops</a></p>
</li>
<li><p><strong>Release v1.3.0 (pós-quântico):</strong> <a href="https://github.com/FiloSottile/age/releases/tag/v1.3.0">github.com/FiloSottile/age/releases/tag/v1.3.0</a></p>
</li>
<li><p><strong>Flux CD + SOPS + age:</strong> <a href="https://fluxcd.io/flux/guides/mozilla-sops/">fluxcd.io/flux/guides/mozilla-sops</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Encrypted DNS: The Guide — DNSCrypt, DNS Stamps, Linux Setup, Android, and the SNI Problem]]></title><description><![CDATA[Every time you type an address in your browser, your device makes a DNS query. By default, that query travels in plaintext to your ISP's resolver. The same ISP that swears it doesn't sell your data bu]]></description><link>https://esli.blog.br/encrypted-dns-the-guide-dnscrypt-dns-stamps-linux-setup-android-and-the-sni-problem</link><guid isPermaLink="true">https://esli.blog.br/encrypted-dns-the-guide-dnscrypt-dns-stamps-linux-setup-android-and-the-sni-problem</guid><category><![CDATA[dnscrypt]]></category><category><![CDATA[dns]]></category><category><![CDATA[Security]]></category><category><![CDATA[DNS over https]]></category><category><![CDATA[DNS over TLS]]></category><category><![CDATA[DNS-over-QUIC]]></category><category><![CDATA[encryption]]></category><category><![CDATA[Cryptography]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Wed, 08 Apr 2026 04:25:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/0e689a9a-8716-4e87-94d9-042a61e0337d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every time you type an address in your browser, your device makes a DNS query. By default, that query travels in plaintext to your ISP's resolver. The same ISP that swears it doesn't sell your data but coincidentally shows you ads for things you searched minutes ago.</p>
<p>This is a comprehensive guide covering the encrypted DNS ecosystem: protocols, DNSCrypt, DNS Stamps, practical setup on Linux and Android, and the SNI leak that undermines everything if left unaddressed.</p>
<hr />
<h2>Traditional DNS: the problem</h2>
<p>DNS (Domain Name System) resolves domain names into IP addresses. It works like a phone book: you ask for the number of <code>esli.blog</code> and get the server's IP. The problem is that this "call" happens without encryption. Anyone in the path — your ISP, the coffee shop admin, an attacker on the same network — can see exactly which domains you're resolving.</p>
<p>The DNS protocol was designed in the 80s, when the internet was an academic environment and the concept of network privacy didn't exist. We're still paying for that design decision.</p>
<hr />
<h2>Encrypted DNS protocols</h2>
<p>Over time, several protocols emerged to fix this. Each with different trade-offs.</p>
<h3>DoT (DNS-over-TLS)</h3>
<p>Wraps DNS queries inside a TLS connection. Uses port 853, dedicated exclusively to this purpose. Standardized in RFC 7858.</p>
<p>Using a dedicated port is a double-edged sword: easy to configure, but also easy to block. A network admin (or government) can simply block port 853 and DoT is gone. Android uses DoT natively via "Private DNS" since version 9, which popularized the protocol on mobile devices.</p>
<h3>DoH (DNS-over-HTTPS)</h3>
<p>Wraps DNS queries inside HTTPS connections, using port 443. Standardized in RFC 8484.</p>
<p>The trick is that DoH traffic blends with regular HTTPS traffic. To block DoH, you'd need to block all HTTPS, which would break the web. This makes it more censorship-resistant, but also harder to monitor in corporate environments (where monitoring may be legitimate). Browsers like Firefox and Chrome support DoH natively.</p>
<h3>DoQ (DNS-over-QUIC)</h3>
<p>Uses the QUIC protocol (which runs over UDP) to transport DNS queries. Standardized in RFC 9250.</p>
<p>More recent, it promises lower latency than DoT/DoH by eliminating the separate TLS+TCP handshake. Still limited adoption, but providers like AdGuard DNS already support it.</p>
<h3>DoH3 (DNS-over-HTTP/3)</h3>
<p>Similar to DoQ, but using HTTP/3 as transport. Since HTTP/3 already uses QUIC, it inherits the same latency advantages. Providers like DNS0 (founded by NextDNS co-founders) already support it.</p>
<h3>ODoH (Oblivious DNS-over-HTTPS)</h3>
<p>An anonymization layer on top of DoH. Uses an intermediary proxy (relay) so the resolver never sees the client's IP. Standardized in RFC 9230.</p>
<p>The concept is similar to Anonymized DNSCrypt (covered below): separate who asks from who answers.</p>
<hr />
<h2>DNSCrypt: the protocol the industry ignored</h2>
<p>DNSCrypt was created by Frank Denis (jedisct1), the same author of libsodium. It's not a "patch" on top of another protocol. It was designed specifically to protect DNS traffic.</p>
<p>What it does:</p>
<ul>
<li><p><strong>Server authentication.</strong> The client validates it's talking to the legitimate resolver using the provider's public key. No dependency on CAs (Certificate Authorities). This eliminates the entire TLS chain of trust, which is a known point of failure.</p>
</li>
<li><p><strong>Query and response encryption.</strong> Uses Curve25519 for key exchange and XSalsa20-Poly1305 (or XChaCha20-Poly1305) for authenticated encryption. All based on elliptic curve cryptography, no dependency on RSA or X.509 certificate infrastructure.</p>
</li>
<li><p><strong>Anti-replay and anti-forgery.</strong> Each query has a unique nonce. Forged or replayed responses are detected and discarded.</p>
</li>
<li><p><strong>Padding.</strong> Queries and responses are padded with random data to hinder traffic analysis based on packet size.</p>
</li>
</ul>
<p>The protocol runs over UDP (port 443 by default) and optionally TCP. It's lightweight, fast, and doesn't depend on PKI infrastructure.</p>
<p>The protocol is in the process of IETF standardization as an Internet-Draft (draft-denis-dprive-dnscrypt-06, updated April 2025).</p>
<h3>Why did the industry ignore it?</h3>
<p>Google, Cloudflare, Apple, Microsoft — they all adopted DoH and DoT. DNSCrypt was left out of the mainstream. Not because it's technically inferior, but because there's no megacorp behind it sponsoring adoption. DoH uses HTTPS, which the entire web infrastructure already supports. DNSCrypt requires its own implementation.</p>
<p>Result: the DNSCrypt <em>protocol</em> has limited adoption among major providers. AdGuard DNS, Quad9, and CleanBrowsing support it. NextDNS, Cloudflare, and Google do not support the DNSCrypt protocol — only DoH and DoT.</p>
<p>But here's the crucial distinction: the DNSCrypt <em>protocol</em> is one thing, the <code>dnscrypt-proxy</code> <em>software</em> is another.</p>
<h3>dnscrypt-proxy: the Swiss army knife</h3>
<p><code>dnscrypt-proxy</code> is the reference client implementation. Written in Go, it runs on practically anything: Linux, macOS, Windows, Android, OpenWrt routers.</p>
<p>The key point is that dnscrypt-proxy is not limited to the DNSCrypt protocol. It supports:</p>
<ul>
<li><p>DNSCrypt v2</p>
</li>
<li><p>DoH (DNS-over-HTTPS)</p>
</li>
<li><p>ODoH (Oblivious DoH)</p>
</li>
<li><p>Anonymized DNSCrypt</p>
</li>
</ul>
<p>So even if a provider doesn't support the DNSCrypt protocol (like NextDNS), you can still use dnscrypt-proxy to connect via DoH. The software accepts stamps from any supported protocol.</p>
<h3>Anonymized DNSCrypt: DNS without tracking</h3>
<p>Encrypted DNS solves the interception problem along the path. But it doesn't solve the problem of the resolver itself knowing who made the query. Your IP arrives at the server alongside the query.</p>
<p>Anonymized DNSCrypt solves this by introducing relays:</p>
<ol>
<li><p>The client encrypts the query for the final resolver (using the resolver's public key).</p>
</li>
<li><p>Sends the encrypted query to a relay.</p>
</li>
<li><p>The relay doesn't have the resolver's key, so it can't read the content. It just forwards the packet.</p>
</li>
<li><p>The resolver receives the query, decrypts it, resolves it, and responds via the relay.</p>
</li>
</ol>
<p>The relay knows the client's IP but not the query content. The resolver knows the query content but only sees the relay's IP. Neither has the complete picture.</p>
<p>This is fundamentally different from using Tor for DNS (which is slow and wasn't designed for it) or blindly trusting that the resolver is "no-log."</p>
<p>The list of available relays is in the <a href="https://github.com/DNSCrypt/dnscrypt-resolvers">official repository</a>.</p>
<hr />
<h2>DNS Stamps: the QR code of DNS</h2>
<p>Manually configuring encrypted DNS is tedious. You need to specify protocol, IP, port, hostname, path (for DoH), public key (for DNSCrypt), and optionally certificate hashes. Multiple fields, each with a different format depending on the protocol.</p>
<p>DNS Stamps solve this by encoding everything into a single string.</p>
<h3>Structure</h3>
<p>A stamp starts with <code>sdns://</code> followed by a base64url payload. The first byte of the payload identifies the protocol:</p>
<table>
<thead>
<tr>
<th>Byte</th>
<th>Protocol</th>
</tr>
</thead>
<tbody><tr>
<td>0x00</td>
<td>Plain DNS</td>
</tr>
<tr>
<td>0x01</td>
<td>DNSCrypt</td>
</tr>
<tr>
<td>0x02</td>
<td>DoH</td>
</tr>
<tr>
<td>0x03</td>
<td>DoT</td>
</tr>
<tr>
<td>0x04</td>
<td>DoQ</td>
</tr>
<tr>
<td>0x05</td>
<td>ODoH target</td>
</tr>
<tr>
<td>0x81</td>
<td>Anonymized DNSCrypt relay</td>
</tr>
<tr>
<td>0x85</td>
<td>ODoH relay</td>
</tr>
</tbody></table>
<p>After the protocol byte, the payload contains properties (DNSSEC, no-log, no-filter), IP address, certificate hashes, hostname, path, and optionally bootstrap IPs.</p>
<h3>Practical example</h3>
<p>A DoH stamp for NextDNS with ID <code>abc123</code>:</p>
<pre><code class="language-plaintext">sdns://AgMAAAAAAAAAAAAADmRucy5uZXh0ZG5zLmlvBy9hYmMxMjM
</code></pre>
<p>Decoded:</p>
<ul>
<li><p>Protocol: 0x02 (DoH)</p>
</li>
<li><p>Hostname: dns.nextdns.io</p>
</li>
<li><p>Path: /abc123</p>
</li>
<li><p>No-log: yes</p>
</li>
<li><p>DNSSEC: yes</p>
</li>
</ul>
<h3>Generating stamps</h3>
<p>The official generator is at <a href="https://dnscrypt.info/stamps/">dnscrypt.info/stamps</a>. Select the protocol, fill in the fields, and the stamp is generated automatically. It works in reverse too: paste a stamp and it decodes the fields.</p>
<p>The DNS Stamps specification is in the process of IETF standardization (draft-denis-dns-stamps-00, July 2025), supporting DNSCrypt, DoH, DoT, DoQ, and ODoH.</p>
<h3>Who publishes stamps natively?</h3>
<p>Not every provider makes life easy. Some publish ready-made stamps in their documentation, others require manual generation.</p>
<table>
<thead>
<tr>
<th>Provider</th>
<th>Stamp in docs</th>
<th>Protocols</th>
</tr>
</thead>
<tbody><tr>
<td>AdGuard DNS</td>
<td>Yes</td>
<td>DNSCrypt, DoH, DoT</td>
</tr>
<tr>
<td>Cloudflare</td>
<td>Yes (listed in dnscrypt-resolvers)</td>
<td>DoH</td>
</tr>
<tr>
<td>Quad9</td>
<td>Yes (listed in dnscrypt-resolvers)</td>
<td>DNSCrypt, DoH</td>
</tr>
<tr>
<td>CleanBrowsing</td>
<td>Yes (listed in dnscrypt-resolvers)</td>
<td>DNSCrypt, DoH</td>
</tr>
<tr>
<td>Mullvad DNS</td>
<td>Yes</td>
<td>DoH</td>
</tr>
<tr>
<td>Control D</td>
<td>Yes</td>
<td>DoH, DoT</td>
</tr>
<tr>
<td>DNS0</td>
<td>Yes</td>
<td>DoH, DoQ</td>
</tr>
<tr>
<td>NextDNS</td>
<td>Yes (Setup &gt; Linux &gt; DNSCrypt)</td>
<td>DoH (via stamp)</td>
</tr>
</tbody></table>
<p><strong>Important note about NextDNS:</strong> contrary to what many think, NextDNS does provide the stamp on the Setup page. Go to <a href="https://my.nextdns.io">my.nextdns.io</a>, access Setup Guide, select Routers, and look for the DNSCrypt section. The stamp is already generated with your config ID. It's a DoH stamp (not native DNSCrypt, since NextDNS doesn't support the DNSCrypt protocol).</p>
<p>To generate manually or add a device name to the path, use the generator at <a href="https://dnscrypt.info/stamps/">dnscrypt.info/stamps</a> with these fields:</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Value</th>
</tr>
</thead>
<tbody><tr>
<td>Protocol</td>
<td>DNS-over-HTTPS</td>
</tr>
<tr>
<td>IP Address</td>
<td>(empty)</td>
</tr>
<tr>
<td>Host name</td>
<td>dns.nextdns.io</td>
</tr>
<tr>
<td>Hashes</td>
<td>(empty)</td>
</tr>
<tr>
<td>Path</td>
<td>/YOUR_ID (e.g., /abc123) or /YOUR_ID/device-name</td>
</tr>
<tr>
<td>No logs</td>
<td>checked</td>
</tr>
<tr>
<td>No filter</td>
<td>unchecked</td>
</tr>
<tr>
<td>DNSSEC</td>
<td>checked</td>
</tr>
</tbody></table>
<p>The path must start with <code>/</code>. If your ID is <code>abc123</code>, the path is <code>/abc123</code>. To identify the device in the dashboard, add a name: <code>/abc123/fedora-desktop</code>.</p>
<p>The complete list of resolvers with ready-made stamps is in the <a href="https://github.com/DNSCrypt/dnscrypt-resolvers">official repository</a>.</p>
<h3>Protocol comparison</h3>
<table>
<thead>
<tr>
<th>Protocol</th>
<th>Port</th>
<th>Transport</th>
<th>Censorship resistance</th>
<th>Depends on CA</th>
<th>Native anonymization</th>
</tr>
</thead>
<tbody><tr>
<td>Do53 (traditional)</td>
<td>53</td>
<td>UDP/TCP</td>
<td>None</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td>DoT</td>
<td>853</td>
<td>TLS</td>
<td>Low (dedicated port)</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>DoH</td>
<td>443</td>
<td>HTTPS</td>
<td>High (blends with HTTPS)</td>
<td>Yes</td>
<td>No (ODoH yes)</td>
</tr>
<tr>
<td>DoQ</td>
<td>853/8853</td>
<td>QUIC</td>
<td>Medium</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>DNSCrypt</td>
<td>443*</td>
<td>UDP/TCP</td>
<td>High</td>
<td>No (own key)</td>
<td>Yes (via relay)</td>
</tr>
</tbody></table>
<p>* Default port 443, but configurable.</p>
<hr />
<h2>Setting up dnscrypt-proxy on Linux</h2>
<h3>Why dnscrypt-proxy instead of the NextDNS CLI?</h3>
<p>NextDNS offers its own CLI (<code>nextdns</code> via <code>sh -c "$(curl -sL https://nextdns.io/install)"</code>). It works fine, it's simple. But dnscrypt-proxy offers advantages:</p>
<ul>
<li><p>Supports multiple protocols (DNSCrypt, DoH, ODoH)</p>
</li>
<li><p>Allows switching providers without changing the stack</p>
</li>
<li><p>Support for Anonymized DNSCrypt and relays</p>
</li>
<li><p>Local cache with configurable TTL</p>
</li>
<li><p>Cloaking, local blocklists, forwarding rules</p>
</li>
<li><p>Detailed logs for debugging</p>
</li>
<li><p>Works identically on any distro</p>
</li>
</ul>
<p>If you just want NextDNS working quickly, the official CLI does the job. If you want granular control or plan to use features beyond what NextDNS offers natively, dnscrypt-proxy is the way.</p>
<h3>Installation</h3>
<p><strong>Fedora:</strong></p>
<pre><code class="language-bash">sudo dnf install dnscrypt-proxy
</code></pre>
<p>The package installs the binary, the systemd service, and the configuration file at <code>/etc/dnscrypt-proxy/dnscrypt-proxy.toml</code>.</p>
<p><strong>Arch / EndeavourOS / Omarchy:</strong></p>
<pre><code class="language-bash">sudo pacman -S dnscrypt-proxy
</code></pre>
<p>Same structure. Arch keeps the package updated frequently.</p>
<p><strong>Debian / Ubuntu:</strong></p>
<pre><code class="language-bash">sudo apt install dnscrypt-proxy
</code></pre>
<p>Warning: versions in Debian/Ubuntu repositories may be outdated. Check with <code>dnscrypt-proxy --version</code> and compare with <a href="https://github.com/DNSCrypt/dnscrypt-proxy/releases">releases on GitHub</a>. If significantly behind, install manually via the GitHub binary.</p>
<h3>Getting the NextDNS stamp</h3>
<p>Two methods:</p>
<p><strong>Method 1 (recommended):</strong> go to <a href="https://my.nextdns.io">my.nextdns.io</a>, navigate to Setup Guide, select Linux or Routers, and copy the stamp from the DNSCrypt section. It already includes your config ID.</p>
<p><strong>Method 2 (manual):</strong> go to <a href="https://dnscrypt.info/stamps/">dnscrypt.info/stamps</a> and fill in:</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Value</th>
</tr>
</thead>
<tbody><tr>
<td>Protocol</td>
<td>DNS-over-HTTPS</td>
</tr>
<tr>
<td>IP Address</td>
<td>(empty)</td>
</tr>
<tr>
<td>Host name</td>
<td>dns.nextdns.io</td>
</tr>
<tr>
<td>Path</td>
<td>/YOUR_ID (e.g., /abc123)</td>
</tr>
<tr>
<td>No logs</td>
<td>checked</td>
</tr>
<tr>
<td>DNSSEC</td>
<td>checked</td>
</tr>
</tbody></table>
<p>Copy the resulting stamp (<code>sdns://...</code>).</p>
<p>To identify the machine in the NextDNS dashboard, add the device name to the path: <code>/abc123/fedora-desktop</code>.</p>
<h3>Configuration</h3>
<p>Edit the main file:</p>
<pre><code class="language-bash">sudo vim /etc/dnscrypt-proxy/dnscrypt-proxy.toml
</code></pre>
<p>Essential settings:</p>
<pre><code class="language-toml"># Listen address
listen_addresses = ['127.0.0.1:53', '[::1]:53']

# Force exclusive use of NextDNS
server_names = ['nextdns']

# Enable IPv6 if your network supports it
ipv6_servers = false

# Require DNSSEC, no-log, and no-filter
require_dnssec = true
require_nofilter = false
require_nolog = true

# Local cache
cache = true
cache_size = 4096
cache_min_ttl = 2400
cache_max_ttl = 86400

# Disable automatic download of public lists
# (we want ONLY NextDNS)
# Comment out or remove [sources] sections if they exist:
# [sources]
#   [sources.'public-resolvers']
#     ...
#   [sources.'relays']
#     ...

# Static server with your stamp
[static]
  [static.'nextdns']
  stamp = 'sdns://AgMAAAAAAAAAAAAADmRucy5uZXh0ZG5zLmlvBy9hYmMxMjM'
</code></pre>
<p>Replace the stamp with the one generated using your real ID.</p>
<p>About the cache: the values above are intentionally aggressive. <code>cache_min_ttl = 2400</code> (40 minutes) and <code>cache_max_ttl = 86400</code> (24 hours) significantly reduce the number of queries to NextDNS. If you're on the free plan (300k queries/month), this makes a difference. Even on the paid plan, fewer queries = less latency for frequently accessed domains.</p>
<h3>The systemd-resolved conflict</h3>
<p>If you're on Fedora, Ubuntu, or any distro using systemd-resolved, brace yourself: it listens on port 53 by default and will conflict with dnscrypt-proxy.</p>
<p>Check before anything:</p>
<pre><code class="language-bash">ss -tlnp | grep ':53 '
</code></pre>
<p>If <code>systemd-resolve</code> shows up listening on 53, you have two options:</p>
<h4>Option A: Disable systemd-resolved (recommended)</h4>
<p>If you want full DNS control and don't need resolved for anything:</p>
<pre><code class="language-bash">sudo systemctl disable --now systemd-resolved
sudo rm /etc/resolv.conf
echo 'nameserver 127.0.0.1' | sudo tee /etc/resolv.conf
sudo chattr +i /etc/resolv.conf
</code></pre>
<p>The <code>chattr +i</code> makes the file immutable. Without it, NetworkManager will overwrite <code>resolv.conf</code> on the first reconnection. To edit later: <code>sudo chattr -i /etc/resolv.conf</code>.</p>
<h4>Option B: Coexistence (dnscrypt-proxy on alternate port)</h4>
<p>If for some reason you need to keep resolved (corporate VPN integration, mDNS/Avahi, etc.):</p>
<p>In <code>dnscrypt-proxy.toml</code>:</p>
<pre><code class="language-toml">listen_addresses = ['127.0.0.1:5353']
</code></pre>
<p>In <code>/etc/systemd/resolved.conf</code>:</p>
<pre><code class="language-ini">[Resolve]
DNS=127.0.0.1#5353
DNSStubListener=yes
</code></pre>
<pre><code class="language-bash">sudo systemctl restart systemd-resolved
</code></pre>
<p>It works, but adds an unnecessary layer. The resolved becomes a middleman that just forwards. Unless you have a concrete reason, go with Option A.</p>
<h4>Note for Arch with Hyprland / Window Managers</h4>
<p>If you don't use NetworkManager and configure networking via <code>iwd</code>, <code>dhcpcd</code>, or manually, systemd-resolved is probably not even active. Check with <code>systemctl status systemd-resolved</code>. If inactive, nothing to do. Just ensure <code>/etc/resolv.conf</code> points to <code>127.0.0.1</code>.</p>
<h3>Persisting resolv.conf on Fedora with NetworkManager</h3>
<p>NetworkManager rewrites <code>/etc/resolv.conf</code> on every reconnection. Besides <code>chattr +i</code>, there's a cleaner approach: tell NetworkManager not to manage DNS.</p>
<p>Create <code>/etc/NetworkManager/conf.d/no-dns.conf</code>:</p>
<pre><code class="language-ini">[main]
dns=none
</code></pre>
<pre><code class="language-bash">sudo systemctl restart NetworkManager
</code></pre>
<p>From here on, NetworkManager doesn't touch DNS. Your <code>resolv.conf</code> with <code>nameserver 127.0.0.1</code> stays intact.</p>
<h3>Enabling and starting</h3>
<pre><code class="language-bash">sudo systemctl enable --now dnscrypt-proxy.service
</code></pre>
<p>Verify:</p>
<pre><code class="language-bash">systemctl status dnscrypt-proxy
journalctl -u dnscrypt-proxy -f
</code></pre>
<p>In the logs, look for lines indicating the <code>nextdns</code> server was validated. Something like:</p>
<pre><code class="language-plaintext">[nextdns] OK (DoH) - rtt: XXms
</code></pre>
<p>If you see stamp errors or server not found, review the stamp and check that no default servers are enabled competing with the static configuration.</p>
<h3>Validation</h3>
<pre><code class="language-bash"># Resolution via dnscrypt-proxy
dig @127.0.0.1 esli.blog

# Confirm NextDNS is active
curl -sL https://test.nextdns.io
</code></pre>
<p>The <code>test.nextdns.io</code> response should show:</p>
<ul>
<li><p>Status: Connected (or Using NextDNS)</p>
</li>
<li><p>Protocol: DoH</p>
</li>
</ul>
<p>If it returns "not using NextDNS", check:</p>
<ul>
<li><p>The stamp (correct path with <code>/YOUR_ID</code>?)</p>
</li>
<li><p>Does <code>server_names</code> point to the correct name?</p>
</li>
<li><p>Is any default server still enabled in sources?</p>
</li>
<li><p>Does <code>resolv.conf</code> point to <code>127.0.0.1</code>?</p>
</li>
</ul>
<p>Also test filtering. Access a domain that should be blocked by your NextDNS blocklists:</p>
<pre><code class="language-bash">dig @127.0.0.1 some-blocked-site.example
</code></pre>
<p>If it returns <code>0.0.0.0</code> or <code>NXDOMAIN</code>, filtering is working.</p>
<h3>Advanced optional configurations</h3>
<h4>Anonymized DNS with relays</h4>
<p>If you want to go further and use relays so NextDNS doesn't see your IP (via Anonymized DoH), add to <code>dnscrypt-proxy.toml</code>:</p>
<pre><code class="language-toml">[anonymized_dns]
routes = [
    { server_name='nextdns', via=['anon-relay-1', 'anon-relay-2'] }
]
</code></pre>
<p>Available relays are in the dnscrypt-proxy resolver list. This adds latency but significantly increases privacy. If NextDNS shouldn't know which IP the queries come from, this is the way.</p>
<h4>Local blocklists</h4>
<p>dnscrypt-proxy supports its own blocklists, independent of NextDNS. In <code>dnscrypt-proxy.toml</code>:</p>
<pre><code class="language-toml">[blocked_names]
blocked_names_file = '/etc/dnscrypt-proxy/blocked-names.txt'
</code></pre>
<p>In <code>blocked-names.txt</code>, add domains (one per line, supports wildcards):</p>
<pre><code class="language-plaintext">*.facebook.com
*.tiktok.com
ads.*
</code></pre>
<p>This works even if NextDNS is down. It's an additional local filtering layer.</p>
<h4>Query logging for debug</h4>
<pre><code class="language-toml">[query_log]
file = '/var/log/dnscrypt-proxy/query.log'
format = 'tsv'
</code></pre>
<p>Create the directory first:</p>
<pre><code class="language-bash">sudo mkdir -p /var/log/dnscrypt-proxy
sudo chown _dnscrypt-proxy:_dnscrypt-proxy /var/log/dnscrypt-proxy
</code></pre>
<p>TSV format makes analysis easy with <code>awk</code>, <code>cut</code>, and friends. Disable in production if privacy is a priority.</p>
<hr />
<h2>Encrypted DNS on Android</h2>
<h3>What Android already offers (and why it's not enough)</h3>
<p>Since Android 9, there's a "Private DNS" option in Settings &gt; Network. It works with DoT (DNS-over-TLS) pointing to a hostname like <code>abc123.dns.nextdns.io</code> (where <code>abc123</code> is your NextDNS config ID).</p>
<p>Does it work? Yes. But it has limitations:</p>
<ul>
<li><p>Only supports DoT. No DoH, no DNSCrypt, no ODoH.</p>
</li>
<li><p>No configurable local cache.</p>
</li>
<li><p>No control over which app uses which DNS.</p>
</li>
<li><p>No integrated firewall.</p>
</li>
<li><p>No configurable fallback.</p>
</li>
<li><p>If the DoT server doesn't respond, Android may fall back to the ISP's DNS silently (depending on the option: "automatic" falls back, "strict" blocks).</p>
</li>
<li><p>No logs for debugging.</p>
</li>
</ul>
<p>For most people, Private DNS with NextDNS in strict mode is already a massive improvement over ISP DNS. But if you want real control, you need something more.</p>
<h3>InviZible Pro: the complete solution</h3>
<p>InviZible Pro is an open-source Android app that integrates three privacy modules in a single package:</p>
<table>
<thead>
<tr>
<th>Module</th>
<th>Underlying software</th>
<th>Function</th>
</tr>
</thead>
<tbody><tr>
<td>DNSCrypt</td>
<td>dnscrypt-proxy</td>
<td>Encrypted DNS</td>
</tr>
<tr>
<td>Tor</td>
<td>tor</td>
<td>Traffic anonymization</td>
</tr>
<tr>
<td>I2P</td>
<td>Purple I2P (i2pd)</td>
<td>I2P network access</td>
</tr>
</tbody></table>
<p>Available on F-Droid (unrestricted version) and Google Play. Source code at <a href="https://github.com/Gedsh/InviZible">GitHub</a> under GPLv3.</p>
<h4>What it does</h4>
<ul>
<li><p><strong>Works with and without root.</strong> With root, redirects traffic via iptables (more efficient, no VPN overhead). Without root, creates a local VPN (traffic doesn't leave the device, it's just redirected internally to the modules).</p>
</li>
<li><p><strong>Integrated firewall.</strong> Granular per-app control: who can use internet, who goes through Tor, who uses direct DNS. Replaces separate firewall apps like NetGuard.</p>
</li>
<li><p><strong>Kill switch.</strong> If the module crashes, traffic is blocked. No accidental plaintext query leaks to the ISP's DNS.</p>
</li>
<li><p><strong>Tor bridges.</strong> Support for obfs4, snowflake, and webtunnel bridges to circumvent censorship on restrictive networks.</p>
</li>
<li><p><strong>Granular configuration.</strong> Direct access to <code>dnscrypt-proxy.toml</code>, <code>torrc</code>, and <code>i2pd.conf</code> files within the app with an integrated text editor.</p>
</li>
<li><p><strong>Real-time logs.</strong> Each module has its own log tab. Debug without needing Termux or logcat.</p>
</li>
<li><p><strong>Independent updates.</strong> The dnscrypt-proxy, Tor, and Purple I2P binaries are updated separately from the app.</p>
</li>
<li><p><strong>Stealth Mode.</strong> DPI (Deep Packet Inspection) evasion for censorship scenarios.</p>
</li>
</ul>
<p>In short: replaces VPN + firewall + DNS adblock in a single app, no ads, no tracking, no subscription for core features.</p>
<h3>Configuring NextDNS in InviZible Pro</h3>
<h4>Prerequisites</h4>
<ul>
<li><p>InviZible Pro installed (F-Droid: <code>pan.alexander.tordnscrypt.stable</code> or Play Store)</p>
</li>
<li><p>NextDNS account with a configured profile</p>
</li>
<li><p>Your config ID (visible at <a href="https://my.nextdns.io">my.nextdns.io</a> in the Setup tab)</p>
</li>
</ul>
<h4>Step 1: Get the stamp</h4>
<p>Same process as described in the DNS Stamps section. Use the stamp from the NextDNS Setup Guide or generate it manually at <a href="https://dnscrypt.info/stamps/">dnscrypt.info/stamps</a>.</p>
<h4>Step 2: Configure via InviZible Pro interface</h4>
<ol>
<li><p>Open InviZible Pro</p>
</li>
<li><p>On the DNSCrypt card, tap the gear icon</p>
</li>
<li><p>Go to DNSCrypt servers and uncheck all pre-configured servers</p>
</li>
<li><p>Go to Own servers / DNS Stamp</p>
</li>
<li><p>Paste the stamp</p>
</li>
<li><p>Name the server (e.g., <code>nextdns</code>)</p>
</li>
<li><p>Save</p>
</li>
</ol>
<h4>Step 2 (alternative): Edit dnscrypt-proxy.toml directly</h4>
<p>If you prefer full control:</p>
<ol>
<li><p>Menu &gt; Common Settings &gt; Open text editor</p>
</li>
<li><p>Select <code>dnscrypt-proxy.toml</code></p>
</li>
<li><p>Edit:</p>
</li>
</ol>
<pre><code class="language-toml">server_names = ['nextdns']

cache = true
cache_size = 4096
cache_min_ttl = 2400
cache_max_ttl = 86400

[static]
  [static.'nextdns']
  stamp = 'sdns://AgMAAAAAAAAAAAAADmRucy5uZXh0ZG5zLmlvBy9hYmMxMjM'
</code></pre>
<ol>
<li>Save and close</li>
</ol>
<h4>Step 3: Restart and validate</h4>
<ol>
<li><p>On the DNSCrypt card, stop and start the module</p>
</li>
<li><p>Check DNSCrypt logs — the <code>nextdns</code> server should appear as active with OK status</p>
</li>
<li><p>In the browser, go to <a href="https://test.nextdns.io">test.nextdns.io</a></p>
</li>
</ol>
<p>If it returns "not using NextDNS": review the stamp (leading <code>/</code> in path? correct config ID?), check no other server is selected, look for error messages in logs.</p>
<h4>Step 4: Additional adjustments</h4>
<p><strong>DNS and Tor together (careful):</strong> if the Tor module is active, DNS queries are routed through Tor by default before reaching NextDNS. This hides your real IP from NextDNS (may be desirable) but increases latency considerably (undesirable for daily use) and may prevent NextDNS from applying location-based rules. To disable: Common Settings &gt; uncheck "Route DNS through Tor."</p>
<p><strong>Battery consumption:</strong> DNSCrypt alone consumes very little. Tor consumes more. If using only the DNSCrypt module (no Tor, no I2P), battery impact is minimal (~8% for Tor + DNSCrypt 24/7 according to InviZible docs). Exclude InviZible Pro from Android's battery optimization. Check <a href="https://dontkillmyapp.com">dontkillmyapp.com</a> for manufacturer-specific instructions (Samsung, Xiaomi/MIUI, and Huawei are the worst offenders).</p>
<p><strong>Rate limit on NextDNS free plan:</strong> 300k queries/month with active filtering. After the limit, DNS continues resolving but without blocking or logs. Aggressive cache (<code>cache_min_ttl = 2400</code>) helps reduce query count. Monitor at <a href="https://my.nextdns.io">my.nextdns.io</a> &gt; Analytics.</p>
<h3>Alternatives to InviZible Pro</h3>
<table>
<thead>
<tr>
<th>Feature</th>
<th>InviZible Pro</th>
<th>personalDNSfilter</th>
<th>AdGuard</th>
<th>Rethink DNS</th>
<th>Private DNS (native)</th>
</tr>
</thead>
<tbody><tr>
<td>DNSCrypt protocol</td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td>DoH</td>
<td>Yes (via stamp)</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>DoT</td>
<td>Not directly</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>DNS Stamps</td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td>Integrated Tor</td>
<td>Yes</td>
<td>No</td>
<td>No</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td>Integrated I2P</td>
<td>Yes</td>
<td>No</td>
<td>No</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td>Per-app firewall</td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Open-source</td>
<td>Yes (GPLv3)</td>
<td>Yes</td>
<td>Partial</td>
<td>Yes</td>
<td>N/A</td>
</tr>
<tr>
<td>Root required</td>
<td>No (local VPN)</td>
<td>No</td>
<td>No</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td>F-Droid</td>
<td>Yes</td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
<td>N/A</td>
</tr>
<tr>
<td>Cost</td>
<td>Free</td>
<td>Free</td>
<td>Paid</td>
<td>Free</td>
<td>Free</td>
</tr>
</tbody></table>
<hr />
<h2>The SNI leak: the Achilles' heel of secure DNS</h2>
<p>You configured DNSCrypt. Enabled DoH. Replaced your ISP's DNS with a privacy-respecting resolver. Did everything right. And yet, your ISP can still know exactly which sites you visit.</p>
<p>Welcome to the SNI problem.</p>
<p>Encrypting DNS queries is the first step toward reclaiming network privacy. But DNS is only half the equation. The other half happens during the TLS handshake, and that's where the leak lives that almost nobody discusses.</p>
<h3>What SNI is and why it exists</h3>
<p>SNI stands for Server Name Indication. It's a field sent by the client (your browser) at the beginning of a TLS connection, <em>before</em> any content encryption.</p>
<p>The reason is practical: when multiple sites share the same IP (extremely common in shared hosting, CDNs, and cloud platforms), the server needs to know which TLS certificate to present. The client provides this by sending the destination hostname in the ClientHello — the first message of the TLS handshake. In plaintext.</p>
<p>This means any entity positioned between you and the destination server (ISP, corporate network operator, government, airport Wi-Fi) can read the SNI field and know exactly which domain you're accessing.</p>
<p>In short: HTTPS protects the content. SNI gives away the destination.</p>
<h3>What the attacker sees (and what they do with it)</h3>
<p>With access to SNI, a network observer can:</p>
<p><strong>Build a complete browsing profile.</strong> Even without seeing page content, knowing that someone accessed <code>medicalconsult.com</code>, <code>jobboard.com</code>, and <code>laborlawyer.com</code> on the same day already tells a story.</p>
<p><strong>Selectively block sites.</strong> South Korea did exactly this in 2019: after users started circumventing DNS blocks, the government instructed ISPs to inspect the SNI field in TLS handshakes to drop connections to prohibited domains. Encrypted DNS became useless. SNI was the new control point.</p>
<p><strong>Censor without breaking encryption.</strong> The ISP doesn't need to decrypt HTTPS traffic. It just reads the SNI, compares it against a list, and drops the SYN packet or sends a RST. Trivial to implement in DPI (Deep Packet Inspection) and invisible to anyone not monitoring.</p>
<p><strong>Correlate traffic with identity.</strong> Combining SNI with source IP and timestamps, it's possible to link access patterns to a specific subscriber. This is done systematically in authoritarian regimes and, as demonstrated in practice, by ISPs in democracies that retain logs by legal obligation.</p>
<p>Encrypted DNS solves the question "which IP does this domain point to?" SNI leaks the answer: "which domain am I visiting?" Two different metadata channels. Protecting one and ignoring the other is like locking the front door and leaving the window wide open.</p>
<h3>The evolution: from ESNI to ECH</h3>
<p>The technical community didn't ignore the problem. The first attempt was <strong>ESNI (Encrypted Server Name Indication)</strong>, proposed in 2018 as an experimental TLS 1.3 extension. The idea was simple: encrypt the SNI field using a public key available via DNS.</p>
<p>ESNI worked as a proof of concept but had practical limitations. Encryption was applied only to the SNI, leaving other ClientHello fields (like ALPN, cipher suite list, and extensions) still visible. This allowed observers to infer destination information even without the explicit SNI. ESNI also depended on specific DNS TXT records, making key distribution fragile and hard to scale.</p>
<p>The answer was <strong>ECH (Encrypted Client Hello)</strong>, which superseded ESNI and is in the final stages of IETF standardization (draft 25 at the time of writing). The fundamental difference: instead of encrypting only the SNI, ECH encrypts the <em>entire</em> ClientHello.</p>
<h3>How ECH works</h3>
<p>ECH splits the ClientHello into two parts:</p>
<p><strong>Outer ClientHello (public):</strong> Contains generic information like TLS version, cipher suites, and a generic SNI. In Cloudflare's case, all ECH connections show <code>cloudflare-ech.com</code> as the external SNI. The network observer sees only that you're accessing "something on Cloudflare," along with millions of other users.</p>
<p><strong>Inner ClientHello (encrypted):</strong> Contains the real SNI, sensitive extensions, and all information that was previously sent in plaintext. This block is encrypted using a public key (ECHConfig) that the browser obtains via HTTPS/SVCB DNS records.</p>
<p>For the ISP or any intermediary, the TLS connection appears to be to <code>cloudflare-ech.com</code>. The real destination is only revealed inside the encrypted tunnel, accessible only to the destination server (or the CDN hosting it).</p>
<p>Think of it this way: without ECH, it's like sending a letter with the recipient's name written on the envelope. With ECH, the envelope shows "Cloudflare" and the real name is inside, sealed.</p>
<h3>The encrypted DNS dependency</h3>
<p>Here's the point that ties everything together: ECH depends on DNS records to function. The browser needs to fetch the domain's HTTPS/SVCB record to obtain the ECHConfig (the encryption public key). If that DNS query is made in plaintext, an attacker can simply remove or modify the record to prevent ECH.</p>
<p>Without DoH, DoT, or DNSCrypt, ECH can be sabotaged before it even starts.</p>
<p>This is why the DNSCrypt setup isn't "just about DNS." It's the foundation for ECH to work. One doesn't replace the other. They complement each other.</p>
<p>The complete chain for real privacy:</p>
<ol>
<li><p><strong>Encrypted DNS</strong> (DNSCrypt, DoH, DoT) → prevents the ISP from knowing which domains you resolve</p>
</li>
<li><p><strong>ECH</strong> → prevents the ISP from knowing which domains you access via TLS</p>
</li>
<li><p><strong>HTTPS</strong> → prevents the ISP from reading the communication content</p>
</li>
</ol>
<p>Remove any of these layers and protection degrades. All three together eliminate browsing metadata visible to network observers.</p>
<h3>Current support: who has implemented it</h3>
<h4>Browsers</h4>
<table>
<thead>
<tr>
<th>Browser</th>
<th>ECH enabled by default</th>
<th>Since</th>
</tr>
</thead>
<tbody><tr>
<td>Firefox</td>
<td>Yes</td>
<td>Version 119 (Oct 2023)</td>
</tr>
<tr>
<td>Chrome</td>
<td>Yes</td>
<td>Version 117+ (gradual rollout)</td>
</tr>
<tr>
<td>Edge</td>
<td>Yes</td>
<td>Follows Chromium</td>
</tr>
<tr>
<td>Brave</td>
<td>Yes</td>
<td>Follows Chromium</td>
</tr>
<tr>
<td>Safari</td>
<td>Yes</td>
<td>macOS Sequoia / iOS 18+</td>
</tr>
<tr>
<td>Tor Browser</td>
<td>Yes</td>
<td>Based on Firefox ESR</td>
</tr>
<tr>
<td>Mullvad Browser</td>
<td>Yes</td>
<td>Based on Firefox</td>
</tr>
</tbody></table>
<p>Firefox was the first to enable ECH by default, and requires DoH to be active for ECH to work (which makes technical sense). Chrome and derivatives do progressive rollout.</p>
<h4>Servers/CDNs</h4>
<p>Cloudflare is the main driver of ECH adoption on the server side. It activated ECH across all plans, including the free tier (where it cannot be disabled). This is relevant because a significant portion of internet sites use Cloudflare as CDN/reverse proxy.</p>
<p>2026 data: approximately 4.2% of the top 100K sites and 9.2% of the top 1M support ECH. Seems low, but considering that Cloudflare alone covers a huge slice of web traffic, the practical impact is larger than the numbers suggest.</p>
<p>Other CDNs and hosting providers are still evaluating. Without server support, ECH simply isn't negotiated and the connection falls back to the old behavior (plaintext SNI).</p>
<h3>How to verify and configure on Linux</h3>
<h4>Firefox</h4>
<p>ECH is already enabled by default in Firefox 119+.</p>
<p>To confirm:</p>
<ol>
<li><p>Go to <code>about:config</code></p>
</li>
<li><p>Search <code>network.dns.echconfig.enabled</code> → should be <code>true</code></p>
</li>
<li><p>Search <code>network.dns.http3_echconfig.enabled</code> → should be <code>true</code></p>
</li>
</ol>
<p>ECH in Firefox depends on DoH being active. Check in: Settings → Privacy &amp; Security → DNS over HTTPS.</p>
<p>Enable with Maximum Protection and select a provider (Cloudflare, NextDNS, or custom).</p>
<h4>Chromium/Brave/Edge</h4>
<p>In Chrome and derivatives, ECH was controlled by a flag until version 117:</p>
<pre><code class="language-plaintext">chrome://flags/#encrypted-client-hello
</code></pre>
<p>Currently, if DoH is active and the server supports ECH, Chrome negotiates automatically and there's no option to disable it.</p>
<p>Again, as with Firefox, ECH depends on Secure DNS being active. Check in: Settings → Privacy and Security → Security → Use secure DNS.</p>
<h4>Checking sites with dig</h4>
<pre><code class="language-bash">dig HTTPS crypto.cloudflare.com +short
</code></pre>
<p>If it returns a field with <code>ech=</code>, the site supports ECH.</p>
<p>The presence of ECHConfig in the HTTPS-type DNS record is a necessary and sufficient condition to confirm server-side ECH support. The browser negotiates if it wants to — but the support is on the server.</p>
<h4>Validation</h4>
<p>To verify ECH is working on your connection:</p>
<ul>
<li><p>Visit <a href="https://crypto.cloudflare.com/cdn-cgi/trace">crypto.cloudflare.com/cdn-cgi/trace</a> and look for the field <code>sni=encrypted</code></p>
</li>
<li><p>Visit <a href="https://defo.ie/ech-check.php">defo.ie/ech-check.php</a> for a more detailed test</p>
</li>
</ul>
<h3>What ECH doesn't solve</h3>
<p>ECH encrypts the ClientHello. That's significant, but it's not the end of the story.</p>
<p><strong>Destination IP.</strong> ECH hides the domain, not the IP. If a server hosts a single site, the IP already reveals the destination. ECH is most effective when many sites share the same infrastructure (as in CDNs).</p>
<p><strong>Traffic analysis.</strong> Data volume, access patterns, and timing are still observable. Traffic fingerprinting techniques can infer the visited site even without SNI.</p>
<p><strong>Unencrypted DNS.</strong> If DNS leaks the domain before ECH kicks in, the protection is null. ECH needs DoH/DoT/DNSCrypt to work as designed.</p>
<p><strong>Servers without support.</strong> If the site you're accessing doesn't support ECH, the SNI remains in plaintext. Protection depends on server-side adoption.</p>
<p>For more complete coverage, combine ECH with a VPN. A VPN hides the destination IP and encapsulates all traffic, while ECH protects TLS metadata. VPN + ECH + encrypted DNS is the most robust combination available today without using Tor.</p>
<h3>ECH as an attack tool</h3>
<p>Worth noting the other side: ECH is also useful for attackers. In 2024, researchers at NTT Security Holdings identified malware (dubbed ECHidna) that used ECH to hide communication with command and control (C2) servers. The malicious traffic masqueraded as legitimate connections to CDN infrastructure, making detection by traditional firewalls ineffective.</p>
<p>This isn't an argument against ECH — on the contrary: it shows the technology and cryptography work. What changes is the intent of use.</p>
<h3>Hiding SNI from your ISP and attackers</h3>
<p><strong>zapret</strong> and <strong>SpoofDPI</strong> are tools that operate at the network layer to prevent Deep Packet Inspection (DPI) systems from reading the SNI field in the TLS ClientHello.</p>
<p>On Linux, zapret uses nfqueue (via iptables/nftables) to intercept outgoing packets before they leave the machine — upon capturing the ClientHello, it applies techniques like TCP fragmentation (split2), TTL manipulation, and fake packet insertion, causing the ISP's DPI to receive fragments out of order or with invalid data while the destination server reassembles correctly.</p>
<p>SpoofDPI acts as a local HTTP/HTTPS proxy: the browser connects to it, and it establishes the real connection with the destination by fragmenting the first TLS packet at the application level — simpler to configure (just point the browser proxy to <code>127.0.0.1:8080</code>), but less flexible than zapret. Neither encrypts nor removes the SNI — they just make passive inspection unfeasible by breaking the heuristics of DPI equipment.</p>
<p>On Android, the main options are <strong>InviZible Pro</strong>, <strong>ByeDPI Android</strong>, and <strong>DPI Tunnel</strong> — all work without root by creating a local VPN on the device that intercepts outgoing traffic and applies fragmentation/desynchronization techniques on the TLS ClientHello before it reaches the ISP, preventing passive DPI from reading the SNI.</p>
<p>InviZible Pro is the most complete, integrating DNSCrypt, Tor, and anti-DPI modules in a single app (with root, it injects direct iptables rules, dispensing with the local VPN and avoiding conflicts). It includes an option to spoof the SNI.</p>
<p>ByeDPI Android is the simplest and most focused: install, choose the desync method (split/disorder), and activate — no extra configuration. As on Linux, none of them encrypt or remove the SNI; they just fragment the TCP packet so that passive inspection equipment can't reassemble and read the field in real time.</p>
<hr />
<h2>Wrapping up</h2>
<p>The complete setup: dnscrypt-proxy on Linux (Fedora, Arch, Debian), InviZible Pro on Android, same NextDNS stamp, same config ID, same blocklists, unified analytics in the NextDNS dashboard. Three environments, one resolver, encrypted queries everywhere.</p>
<p>But remember: encrypted DNS alone is not enough. The SNI leak exposes your browsing destinations during TLS handshakes. ECH is the fix, but adoption is still in progress. Browser support is already universal. Cloudflare pushes server-side adoption. The pieces are falling into place.</p>
<p>What you control directly:</p>
<ol>
<li><p><strong>Enable DoH/DoT/DNSCrypt</strong> — the prerequisite for ECH to function</p>
</li>
<li><p><strong>Validate ECH is active</strong> in your browser (<code>about:config</code>, flags, online tests)</p>
</li>
<li><p><strong>Disable WebRTC</strong> — not SNI directly, but WebRTC leaks your real IP even with VPN/ECH, enabling correlation</p>
</li>
</ol>
<p>Without ECH, SNI is the last open metadata channel for network observers. With ECH, that channel closes. The ISP stops knowing which site you visit — not just what you do inside it.</p>
<p>If your ISP could charge for every DNS query it snoops on, it would have funded a space program by now. Encrypt your queries. And while you're at it, push for ECH adoption.</p>
<hr />
<h2>References</h2>
<ul>
<li><p><a href="https://dnscrypt.info/">DNSCrypt project</a></p>
</li>
<li><p><a href="https://dnscrypt.info/stamps-specifications/">DNS Stamps specification</a></p>
</li>
<li><p><a href="https://github.com/DNSCrypt/dnscrypt-proxy">dnscrypt-proxy on GitHub</a></p>
</li>
<li><p><a href="https://github.com/DNSCrypt/dnscrypt-resolvers">dnscrypt-resolvers</a></p>
</li>
<li><p><a href="https://github.com/Gedsh/InviZible">InviZible Pro on GitHub</a></p>
</li>
<li><p><a href="https://www.ietf.org/archive/id/draft-denis-dprive-dnscrypt-06.html">IETF Draft: DNSCrypt</a></p>
</li>
<li><p><a href="https://www.ietf.org/archive/id/draft-denis-dns-stamps-00.html">IETF Draft: DNS Stamps</a></p>
</li>
<li><p><a href="https://datatracker.ietf.org/doc/draft-ietf-tls-esni/">IETF Draft: ECH</a></p>
</li>
<li><p><a href="https://www.rfc-editor.org/rfc/rfc8744">RFC 8744 — Issues and Requirements for SNI Encryption in TLS</a></p>
</li>
<li><p><a href="https://blog.cloudflare.com/announcing-encrypted-client-hello/">Cloudflare: Announcing Encrypted Client Hello</a></p>
</li>
<li><p><a href="https://www.cloudflare.com/learning/dns/dns-over-tls/">Cloudflare: DNS over TLS</a></p>
</li>
<li><p><a href="https://cdt.org/">CDT — Encrypted Client Hello: Closing the SNI Metadata Gap</a></p>
</li>
<li><p><a href="https://defo.ie/ech-check.php">ECH check tool</a></p>
</li>
<li><p><a href="https://crypto.cloudflare.com/cdn-cgi/trace">Cloudflare trace</a></p>
</li>
<li><p><a href="https://my.nextdns.io">NextDNS dashboard</a></p>
</li>
<li><p><a href="https://test.nextdns.io">NextDNS test</a></p>
</li>
<li><p><a href="https://dontkillmyapp.com">Don't Kill My App</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[The Ultimate YubiKey Guide and Setup for Linux]]></title><description><![CDATA[I wrote a series of articles about YubiKey over the past few years. The original idea was simple: move from "2FA because I have to" to "2FA/MFA by architecture." Along the way, the key stopped being a]]></description><link>https://esli.blog.br/the-ultimate-yubikey-guide-and-setup-for-linux</link><guid isPermaLink="true">https://esli.blog.br/the-ultimate-yubikey-guide-and-setup-for-linux</guid><category><![CDATA[yubikey]]></category><category><![CDATA[yubikeys]]></category><category><![CDATA[SRE]]></category><category><![CDATA[Security]]></category><category><![CDATA[Devops]]></category><category><![CDATA[2FA]]></category><category><![CDATA[MFA]]></category><category><![CDATA[token]]></category><category><![CDATA[encryption]]></category><category><![CDATA[Cryptography]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Tue, 07 Apr 2026 03:19:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/4208126b-da2f-4d9f-a178-b6e1b8df45dc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I wrote a series of articles about YubiKey over the past few years. The original idea was simple: move from "2FA because I have to" to "2FA/MFA by architecture." Along the way, the key stopped being an expensive trinket and became a useful component of a coherent setup: hardened Linux, SSH less dependent on sensitive files, GPG less exposed, and authentication more resistant to phishing.</p>
<p>This post is a unified summary of the original series, with direct references, and with technical updates that make sense in 2026 — especially around FIDO2/WebAuthn, passkeys, and PIN/management policies that have evolved significantly. I also connect it with my other posts on cryptography, because YubiKey is a practical consequence: you stop talking about "crypto" as an abstract concept and start operationalizing keys, signatures, identity, and risk.</p>
<h3>Before anything: YubiKey is not "improved 2FA"</h3>
<p>The temptation is to treat YubiKey as "the same 2FA, just on USB." That reduces the subject to the worst use case: typeable OTP, user-dependent, exposed to phishing and clunky UX. The real value appears when you understand it supports multiple protocols, and each one changes the type of attack you need to defeat.</p>
<p>When you move from codes to FIDO2/WebAuthn, for example, you're not "improving 2FA" — you're changing the category: authentication becomes bound to the origin (the site), which drastically reduces the class of attacks based on fake pages and reusable secret harvesting. When you bring the key to SSH, you reduce the impact of <code>$HOME</code> theft/exfiltration. When you bring it to OpenPGP, you decrease key material exposure and improve your discipline around subkeys and purposes.</p>
<h3>2FA/MFA — The Basics</h3>
<p>Two-factor authentication is an additional security layer that requires at least two of the following:</p>
<ul>
<li><p><strong>What you know</strong> — passwords, PINs</p>
</li>
<li><p><strong>What you have</strong> — a physical device, a card</p>
</li>
<li><p><strong>Who you are</strong> — biometrics</p>
</li>
</ul>
<p>An ATM withdrawal covers two: you know your PIN and have your debit card. A bank vault can use all three, with passwords, access cards, and fingerprint scans required to open it.</p>
<p>Traditional email and password logins cover only the first — what you know. You know your email address and password, and generally, they're easy enough for someone else to guess or crack. That's what makes them so insecure. Two-factor authentication adds a second layer to digital logins.</p>
<p>Almost every service now allows users to enable two-factor authentication. We're at a turning point where having 2FA enabled is mandatory in more and more services and apps.</p>
<p>Passwords are terrible. Most are too easy for hackers to guess, and the rest are too long or complicated for humans to remember. Even secure passwords are useless after a leak, and leaks are basically inevitable. For these reasons and more, it's a good idea not to rely exclusively on passwords.</p>
<h3>2FA Methods</h3>
<p><strong>SMS or email codes</strong> — Apps send a code you need to enter before logging in. Easiest to set up because you don't need to install software or buy hardware. Also the least secure because email and SMS are not encrypted and are easily compromised.</p>
<p><strong>Authenticator apps</strong> — The apps you want to log into request a code you can retrieve by opening an app on your phone, like Google Authenticator or Authy. Much more secure than relying on SMS or email, but not exactly convenient — you need to grab your phone, open an app, and type a code.</p>
<p><strong>Hardware authentication</strong> — Apps ask you to plug in a device like a YubiKey and press a button. The YubiKey sends a unique code that the service uses to confirm your identity. More secure because the codes are much longer and more convenient (SMS/token codes are typically 4-6 numeric digits), and you don't need to type them yourself.</p>
<h3>What is a YubiKey?</h3>
<p>The YubiKey is a device that makes two-factor authentication as simple as possible. Instead of a code being sent to you (SMS) or generated by an app on your phone (Authy, Authenticator, bank tokens...), you just press a button on your YubiKey.</p>
<p>Each device has a unique built-in code used to generate codes that help confirm your identity. YubiKey is not the only hardware 2FA device on the market — just the most popular.</p>
<p><strong>Why is it better?</strong></p>
<ul>
<li><p><strong>Convenience</strong> — SMS, email, and authenticator apps require you to copy-paste or manually enter a code. With YubiKey, just press a button on a device connected to your computer.</p>
</li>
<li><p><strong>Much longer codes</strong> — Other 2FA methods typically send only a six-digit code. YubiKeys don't ask you to type a code manually, so they can use much longer codes. More secure.</p>
</li>
<li><p><strong>Easy to migrate</strong> — New computer? Unplug your YubiKey from the old one, plug it into the new one, and log into all your apps as before. You can also use one key to log into your account on multiple computers.</p>
</li>
<li><p><strong>Extremely hard to hack</strong> — It's relatively easy for hackers to compromise your email or SMS. It's much harder — nearly impossible with current technology — to forge the codes generated by a unique hardware device.</p>
</li>
</ul>
<p>How it works: <a href="https://www.yubico.com/why-yubico/how-the-yubikey-works/">yubico.com/why-yubico/how-the-yubikey-works</a></p>
<p>Catalog of supported services/sites/apps: <a href="https://www.yubico.com/br/works-with-yubikey/catalog/?sort=popular">yubico.com/works-with-yubikey/catalog</a></p>
<h3>YubiKey 5 NFC — Overview</h3>
<p>Released in 2018. Primary functions:</p>
<ul>
<li><p><strong>FIDO2</strong> — Secure single and multi-factor authentication, stores up to 25 credentials protected by a PIN. Enables passwordless login where the YubiKey, unlocked by PIN and authorized by touch, can log into accounts without entering a username or password. FIDO certified.</p>
</li>
<li><p><strong>OTP</strong> — Two programmable slots, each can hold: Yubico OTP, HMAC-SHA1 Challenge-Response, Static Password, or OATH-HOTP.</p>
</li>
<li><p><strong>U2F</strong> — Unlimited U2F credentials. FIDO certified.</p>
</li>
<li><p><strong>OATH</strong> — Up to 32 OATH credentials, supports OATH-TOTP (time-based) and OATH-HOTP (counter-based). Requires Yubico Authenticator.</p>
</li>
<li><p><strong>PIV (Smart Card)</strong> — PIV-compatible smart card. Supported algorithms: RSA 1024/2048, ECC P256/P384. Slots: 9a (Authentication), 9b (Management Key), 9c (Digital Signature), 9d (Key Management), 9e (Card Authentication), f9 (Attestation), 82-95 (Retired Key Management).</p>
</li>
<li><p><strong>OpenPGP</strong> — Implements OpenPGP Smart Card spec v2.0 (v3.4 on firmware 5.2.3+). Supported algorithms: RSA 1024-4096, secp256r1, secp256k1, secp384r1, secp521r1, brainpoolP256r1/384r1/512r1, curve25519, x25519 (decrypt only), ed25519 (sign/auth only). GnuPG 2.0+ required for keys above 2048 bits.</p>
</li>
<li><p><strong>Differentiator:</strong> NFC</p>
</li>
</ul>
<p>For SRE/DevOps context, the most relevant protocols are: <strong>PIV, OpenPGP, HMAC-CR, and FIDO2</strong>. The private key never leaves the chip — the app sends data to the YubiKey for processing; it returns the result. That's what differentiates an HSM from a <code>.pem</code> file on disk.</p>
<h3>Linux Installation</h3>
<p>The YubiKey works out of the box — no drivers needed. Plug it into a USB port (gold contacts facing up on most computers), and the LED should light up solid green. It uses standard USB keyboard drivers.</p>
<p>On Linux, the key is recognized as a QWERTY keyboard input to enter the generated code when you touch the gold surface (the area with the "Y" logo).</p>
<p>You can use it with any software token generator (Google Authenticator, Authy, LastPass Authenticator, etc.), but for full functionality (OATH via Authenticator, PIV, OpenPGP), you'll need the smartcard stack.</p>
<p><strong>Installing pcscd</strong></p>
<p>The <code>pcscd</code> daemon is middleware for accessing smart cards — it allocates/deallocates reader drivers dynamically at runtime and manages connections.</p>
<pre><code class="language-bash"># Debian/Ubuntu
sudo apt-get install pcscd

# Arch
sudo pacman -S yubikey-manager ykpers libfido2 pcsc-tools opensc

# Fedora
sudo dnf install yubikey-manager ykpers libfido2 pcsc-lite opensc
</code></pre>
<p>If installing via Snap or adding Yubico repositories on Ubuntu, <code>pcscd</code> is not required separately.</p>
<p><strong>Verify the key is present:</strong></p>
<pre><code class="language-bash">ykman info
</code></pre>
<h3>Yubico Apps</h3>
<p><strong>Yubico Authenticator</strong> — Complements the YubiKey for sites/apps that don't support hardware as an authenticator. You scan the QR code (or register manually) and it generates the numeric token requested after successful password login. Available for desktop and mobile (Android/iOS). It requires the YubiKey and PIN to open and display tokens.</p>
<pre><code class="language-bash">sudo snap install yubioath-desktop
</code></pre>
<p>Downloads: <a href="https://www.yubico.com/products/yubico-authenticator/#h-download-yubico-authenticator">Yubico Authenticator</a> | <a href="https://snapcraft.io/install/yubioath-desktop">Snap</a></p>
<p><strong>YubiKey Manager</strong> — Optional. For configuring tokens and managing slots. Available as AppImage and CLI.</p>
<pre><code class="language-bash"># Ubuntu
sudo add-apt-repository ppa:yubico/stable &amp;&amp; sudo apt-get update

# CLI
sudo apt install yubikey-manager

# Personalization Tool
sudo apt install yubikey-personalization-gui

# PAM modules
sudo apt install libpam-yubico libpam-u2f
</code></pre>
<p>Downloads: <a href="https://www.yubico.com/support/download/yubikey-manager/">YubiKey Manager</a> | <a href="https://developers.yubico.com/yubikey-manager-qt/Releases/">Releases</a></p>
<h3>Configuring Your YubiKey</h3>
<p>Each site/service/app has its own path to enable the key, usually in security settings near the password change option. Services that don't support the physical key support 2FA via app.</p>
<p>Yubico maintains a knowledge base with step-by-step instructions for configuring your key on various services:</p>
<ol>
<li><p>Plug in your YubiKey</p>
</li>
<li><p>Go to <a href="https://www.yubico.com/br/setup/yubikey-5-series/">yubico.com/setup</a> and click your device</p>
</li>
<li><p>Browse the list of compatible apps</p>
</li>
<li><p>Follow the instructions</p>
</li>
</ol>
<h3>Yubico API</h3>
<p>To get your API ID and Secret, enter an email and touch the key at: <a href="https://upgrade.yubico.com/getapikey/">upgrade.yubico.com/getapikey</a></p>
<p>Despite the name "upgrade", the API is free.</p>
<pre><code class="language-plaintext">Client ID:  58107
Secret key: 8xpmpAy2OtmZAAeXP/0NUed/aLB=
</code></pre>
<h3>PAM Configuration — libpam-yubico</h3>
<p>There are two ways to configure PAM authentication: <code>libpam-yubico</code> and <code>libpam-u2f</code>. You can configure both on the same host, but each file in <code>pam.d</code> should use only one method (no point in requiring two tokens for the same login).</p>
<p><strong>Create the authentication file</strong> at <code>/etc/yubikeys_mappings</code>:</p>
<pre><code class="language-plaintext">#username:first12charsofkey
esl1h:ccccedrrdvhv
</code></pre>
<p>If a user has more than one key, separate the first 12 characters of each with a semicolon. One line per user.</p>
<p>Optionally, keep an individual file in each user's home: <code>~/.yubico/authorized_yubikeys</code>. If the key file is omitted in <code>pam.d</code> config, it will look in the user's home.</p>
<p><strong>Add the ID and Secret:</strong></p>
<pre><code class="language-bash">sudo dpkg-reconfigure libpam-yubico
</code></pre>
<p>On the next screen (PAM enable profile), keep the defaults.</p>
<h3>PAM Configuration — libpam-u2f</h3>
<pre><code class="language-bash">sudo apt install libpam-u2f pamu2fcfg

# Create config directory
mkdir -p ~/.config/Yubico

# Generate authentication config
pamu2fcfg &gt; ~/.config/Yubico/u2f_keys
</code></pre>
<p>If you registered a PIN on the key, it will be requested. Then touch the key and it will populate the file.</p>
<h3>Common PAM Setup</h3>
<p>For both configurations above, in <code>/etc/pam.d/common-auth</code>, add <code>try_first_pass</code> as a parameter to <code>pam_unix.so</code>:</p>
<pre><code class="language-plaintext">auth [success=1 default=ignore]  pam_unix.so nullok_secure try_first_pass
</code></pre>
<h3>YubiKey for Console Login</h3>
<p>Add at the beginning of <code>/etc/pam.d/login</code>:</p>
<pre><code class="language-plaintext"># Using libpam-yubico (shows prompt for key):
auth sufficient pam_yubico.so id=58107
# Replace with YOUR ID!

# OR using libpam-u2f (no visual prompt, key LED blinks):
auth required pam_u2f.so
</code></pre>
<p>The difference: <code>libpam-yubico</code> presents a prompt asking for the key; with <code>pam_u2f</code>, nothing visual is shown — only the key's LED blinks, indicating you should touch it.</p>
<p>This does <strong>not</strong> modify the graphical interface login, only the console terminal login.</p>
<h3>2FA for sudo</h3>
<p>With <code>libpam-u2f</code> configured, edit <code>/etc/pam.d/sudo</code>. Right below the <code>@include common-auth</code> line, add:</p>
<pre><code class="language-plaintext">auth required pam_u2f.so
</code></pre>
<p>When running <code>sudo</code>: enter password + [Enter], then touch the key to insert the token.</p>
<h3>SSH with PAM</h3>
<p>With <code>pam_u2f</code> configured, add to <code>/etc/pam.d/sshd</code> below <code>@include common-account</code>:</p>
<pre><code class="language-plaintext">auth       required   pam_u2f.so
</code></pre>
<p><strong>Important caveat:</strong> this only works on localhost. For remote hosts, additional configuration and <code>sshd_config</code> parameters are needed for a proper SSH + 2FA environment. Alternatives: use YubiKey with FIDO U2F to generate the SSH key, or use only the YubiKey token for SSH login (without password, key, or 2FA) through PGP or PIV.</p>
<h3>OpenSSH with YubiKey + ed25519</h3>
<p>Since OpenSSH 8.2 (released 2020), U2F/FIDO devices are supported using the <code>ecdsa-sk</code> and <code>ed25519-sk</code> public key types (FIDO2, YubiKeys with firmware above 5.2.3) and their certificates. The <code>sk</code> stands for "Security Key."</p>
<p><strong>Check your YubiKey firmware version:</strong></p>
<pre><code class="language-bash">lsusb -v 2&gt;/dev/null | grep -A2 Yubico | grep "bcdDevice" | awk '{print $2}'
</code></pre>
<p>Above 5.2.3 = FIDO2 support.</p>
<p><strong>The advantage:</strong> you get a normal public/private key pair, but the private key file doesn't contain the actual sensitive private key — instead, it contains a "key handle" used by the YubiKey to derive the real private key at signing time.</p>
<pre><code class="language-plaintext">ssh user@host -i .ssh/id_ed25519_sk [+ passphrase] [+ yubikey-token]
</code></pre>
<p>Even if the key leaks, it's not enough to access the host (even knowing the username).</p>
<p><strong>Why ed25519 over ECDSA:</strong> ECDSA has known vulnerabilities. RSA 4096-bit has comparable complexity to Ed25519, but Ed25519 is still preferred due to concerns that RSA may be vulnerable to the same strength concerns as DSA.</p>
<p><strong>Generate keys:</strong></p>
<pre><code class="language-bash"># ECDSA-SK
ssh-keygen -t ecdsa-sk -f ~/.ssh/id_ecdsa_sk

# Ed25519-SK (preferred)
ssh-keygen -t ed25519-sk -f ~/.ssh/id_ed25519_sk

# FIDO2 resident key (stored on YubiKey, portable)
ssh-keygen -t ed25519-sk -O resident -O verify-required \
    -C "esli@infra-prod" -f ~/.ssh/id_ed25519_yk

# Export handles from resident keys (use on another host without the file)
ssh-keygen -K

# Add to ssh-agent with mandatory touch confirmation
ssh-add -K ~/.ssh/id_ed25519_yk
</code></pre>
<p>After generating keys, add the public key (<code>.pub</code>) to <code>authorized_keys</code> on the server and/or add via ssh-agent (<code>ssh-agent</code>, <code>ssh-add</code>).</p>
<p><strong>Force the SSH server to accept only YubiKey-generated keys:</strong></p>
<p>In <code>/etc/ssh/sshd_config</code>:</p>
<pre><code class="language-plaintext">PubkeyAcceptedKeyTypes sk-ecdsa-sha2-nistp256@openssh.com,sk-ssh-ed25519@openssh.com
# Or ed25519 only:
# PubkeyAcceptedKeyTypes sk-ssh-ed25519@openssh.com
</code></pre>
<h3>GPG Keys</h3>
<h4>Creating RSA Keys</h4>
<pre><code class="language-bash">gpg --gen-key
# Or with full options:
gpg --expert --full-generate-key
</code></pre>
<p>Choose: (1) RSA and RSA, 4096 keysize, 3072 for subkeys, expiration as desired, then fill in identification data and set a password.</p>
<pre><code class="language-plaintext">pub   rsa4096 2023-02-02 [SC]
      F40975F47855887B2084E7D18A74F970158F02B8
uid                      Esli Silva (https://esli.blog.br) &lt;not.announced@simplelogin.fr&gt;
sub   rsa3072 2023-02-02 [E]
</code></pre>
<h4>Encrypting/Decrypting with GPG</h4>
<pre><code class="language-bash"># Encrypt (no password prompt — uses public key)
gpg -r F40975F47855887B2084E7D18A74F970158F02B8 -e -a -o Encrypted.pdf Original.pdf

# Decrypt (requires key + password; import key first on other hosts)
gpg -r F40975F47855887B2084E7D18A74F970158F02B8 -d -o Decrypted.pdf Encrypted.pdf
</code></pre>
<h4>Adding Subkeys</h4>
<pre><code class="language-bash">gpg --expert --edit-key F40975F47855887B2084E7D18A74F970158F02B8
</code></pre>
<p>At the <code>gpg&gt;</code> prompt:</p>
<pre><code class="language-plaintext">gpg&gt; addkey
# Select option (8) RSA (set your own capabilities)
# Toggle S/E/A to set desired capabilities
# S = Sign, E = Encrypt, A = Authenticate
</code></pre>
<p><strong>The same key should NEVER be used for different purposes.</strong> The subkey format exists precisely to separate signing, encryption, and authentication — this improves security and your ability to operate with discipline (revoke, rotate, isolate).</p>
<p>RSA keypairs in PGP can still have all capability bits at once, but all other key types explicitly use different algorithms for signing and encryption — an ECDSA or EdDSA key can only sign/verify, and an ECDH key can only encrypt/decrypt. Since the master key in PGP is used to certify other people's keys and your own subkeys, it must be a signing-capable algorithm (certify).</p>
<p>After setting capabilities and confirming, save:</p>
<pre><code class="language-plaintext">gpg&gt; quit
Save changes? (y/N) y
</code></pre>
<h4>Backup/Export GPG Keys</h4>
<pre><code class="language-bash"># Export secret key to stdout
gpg --export-secret-key --armor F40975F47855887B2084E7D18A74F970158F02B8

# Export public key to file
gpg --output public.pgp --armor --export F40975F47855887B2084E7D18A74F970158F02B8

# Export private key to file
gpg --output private.pgp --armor --export-secret-key F40975F47855887B2084E7D18A74F970158F02B8
</code></pre>
<h4>Creating ECC Keys</h4>
<p>Same steps, selecting ECC at the start:</p>
<pre><code class="language-bash">gpg --expert --full-generate-key
# Select (11) ECC (set your own capabilities)
# Toggle capabilities as needed (S, A, Q to finish)
# Select (1) Curve 25519
# Set expiration, fill identification data
</code></pre>
<pre><code class="language-plaintext">pub   ed25519 2023-02-02 [SCA]
      C512D2E3863F0D4902D63EC5BAB622429963AB29
uid                      Esli Silva (https://esli.blog.br) &lt;my.develoment@aleeas.com&gt;
</code></pre>
<p>When editing an ECC key and calling <code>addkey</code>, the option (8) with multiple capabilities is no longer available — ECC enforces algorithm separation by design.</p>
<h4>Listing GPG Keys</h4>
<pre><code class="language-bash">gpg --list-keys
</code></pre>
<h4>Importing Keys to YubiKey</h4>
<pre><code class="language-bash">gpg --edit-key F40975F47855887B2084E7D18A74F970158F02B8
</code></pre>
<pre><code class="language-plaintext">gpg&gt; keytocard
Really move the primary key? (y/N) y
Please select where to store the key:
   (1) Signature key
   (3) Authentication key
Your selection? 3
</code></pre>
<h4>GPG with YubiKey for File/Secrets Encryption</h4>
<pre><code class="language-bash"># Check if YubiKey is recognized as GPG card
gpg --card-status

# Encrypt file to your own key (on YubiKey)
gpg --encrypt --recipient esli@esli.blog.br secrets.txt

# Decrypt — YubiKey performs the operation, requires PIN
gpg --decrypt secrets.txt.gpg &gt; secrets.txt

# Practical: secrets in a Git repo
echo "DB_PASSWORD=hunter2" | gpg --encrypt -r esli@esli.blog.br --armor &gt; .secrets.gpg
# At deploy time:
gpg --decrypt .secrets.gpg | source /dev/stdin
</code></pre>
<h3>HMAC-SHA1 Challenge-Response for Key Derivation</h3>
<p>Slot 2 of the YubiKey can be configured for HMAC-CR. You send a challenge (up to 64 bytes), it returns a 20-byte HMAC. This becomes the basis for an encryption key.</p>
<p><strong>Encrypt:</strong></p>
<pre><code class="language-bash">#!/usr/bin/env bash
# yk-encrypt.sh — Encrypt file using YubiKey as key factor
set -euo pipefail

FILE="\({1:?Usage: \)0 &lt;file&gt;}"
SLOT=2

# Generate random challenge and save alongside encrypted file
CHALLENGE=$(openssl rand -hex 32)
echo "[*] Sending challenge to YubiKey (slot $SLOT)..."

# ykchalresp returns HMAC in hex
HMAC=\((ykchalresp -2 "\)CHALLENGE" 2&gt;/dev/null) || {
    echo "[!] YubiKey did not respond. Inserted and configured?" &gt;&amp;2
    exit 1
}

# Derive AES-256 key via PBKDF2 (challenge + HMAC as material)
KEY=\((echo -n "\){CHALLENGE}${HMAC}" | openssl dgst -sha256 -binary | xxd -p -c 256)

# Encrypt with AES-256-CBC
openssl enc -aes-256-cbc -pbkdf2 -iter 600000 \
    -k "$KEY" \
    -in "$FILE" \
    -out "${FILE}.yk.enc"

# Save the challenge (without the HMAC — without the physical key, can't open)
echo "\(CHALLENGE" &gt; "\){FILE}.yk.challenge"

echo "[+] Encrypted file: ${FILE}.yk.enc"
echo "[+] Challenge saved: ${FILE}.yk.challenge"
echo "[!] Without the YubiKey, the file cannot be decrypted."
</code></pre>
<p><strong>Decrypt:</strong></p>
<pre><code class="language-bash">#!/usr/bin/env bash
# yk-decrypt.sh
set -euo pipefail

ENC_FILE="\({1:?Usage: \)0 &lt;file.yk.enc&gt;}"
CHALLENGE_FILE="${ENC_FILE%.enc}.challenge"
SLOT=2

CHALLENGE=\((cat "\)CHALLENGE_FILE")
echo "[*] Waiting for YubiKey..."
HMAC=\((ykchalresp -2 "\)CHALLENGE" 2&gt;/dev/null) || { echo "[!] YubiKey failed" &gt;&amp;2; exit 1; }

KEY=\((echo -n "\){CHALLENGE}${HMAC}" | openssl dgst -sha256 -binary | xxd -p -c 256)

openssl enc -d -aes-256-cbc -pbkdf2 -iter 600000 \
    -k "$KEY" \
    -in "$ENC_FILE" \
    -out "${ENC_FILE%.yk.enc}.decrypted"

echo "[+] Decrypted: ${ENC_FILE%.yk.enc}.decrypted"
</code></pre>
<h3>Protocol Quick Reference</h3>
<table>
<thead>
<tr>
<th>Need</th>
<th>Protocol</th>
<th>Tool/Lib</th>
</tr>
</thead>
<tbody><tr>
<td>File encryption</td>
<td>PIV (RSA/ECDH) or OpenPGP</td>
<td><code>age-plugin-yubikey</code>, <code>gpg</code>, <code>piv-go</code>, <code>yubikey</code> (Rust)</td>
</tr>
<tr>
<td>SSH without password</td>
<td>FIDO2 (<code>ed25519-sk</code>)</td>
<td><code>ssh-keygen -t ed25519-sk</code></td>
</tr>
<tr>
<td>2FA on web apps</td>
<td>FIDO2/WebAuthn</td>
<td><code>fido2</code> (Python), <code>webauthn</code> (Go/Rust)</td>
</tr>
<tr>
<td>Key derivation (disk, vault)</td>
<td>HMAC-SHA1 CR</td>
<td><code>ykchalresp</code>, <code>libykpers</code>, <code>yubikey-manager</code></td>
</tr>
<tr>
<td>Code/commit signing</td>
<td>OpenPGP</td>
<td><code>gpg --card-status</code></td>
</tr>
<tr>
<td>Legacy system auth</td>
<td>OTP (HOTP/TOTP)</td>
<td><code>ykman oath</code></td>
</tr>
<tr>
<td>Privileged access with PIN</td>
<td>PIV</td>
<td><code>piv-go</code>, <code>yubikey</code> (Rust), <code>opensc</code></td>
</tr>
</tbody></table>
<h3>What Protocols Are Available?</h3>
<table>
<thead>
<tr>
<th>Protocol</th>
<th>Interface</th>
<th>Typical Use</th>
</tr>
</thead>
<tbody><tr>
<td>OTP (Yubico OTP / HOTP / TOTP)</td>
<td>HID (keyboard)</td>
<td>Classic 2FA</td>
</tr>
<tr>
<td>FIDO2 / WebAuthn</td>
<td>HID</td>
<td>Passwordless login</td>
</tr>
<tr>
<td>U2F</td>
<td>HID</td>
<td>2FA on web apps</td>
</tr>
<tr>
<td>PIV (Smart Card)</td>
<td>CCID</td>
<td>Encryption, SSH, certificates</td>
</tr>
<tr>
<td>OpenPGP</td>
<td>CCID</td>
<td>GPG, file encryption</td>
</tr>
<tr>
<td>HMAC-SHA1 Challenge-Response</td>
<td>HID</td>
<td>Key derivation, disk encryption</td>
</tr>
<tr>
<td>OATH (TOTP/HOTP)</td>
<td>CCID</td>
<td>OTP generation via app</td>
</tr>
</tbody></table>
<h3>Real-World YubiKey Applications for SRE/DevOps</h3>
<p>In the real world, YubiKey stops being "just another authentication factor" and becomes a physical control point over critical actions. In infrastructure environments, this completely changes the threat model: compromising credentials isn't enough — the attacker also needs the physical device.</p>
<p><strong>Privileged SSH access</strong> — Instead of relying on private keys stored on the filesystem (even with correct permissions), authentication requires physical presence and operator interaction. This eliminates an entire class of attacks based on key exfiltration (malware, compromised backups, home directory leaks). In environments with bastion hosts or access to sensitive Kubernetes clusters, this drastically reduces the risk of silent lateral movement.</p>
<p><strong>Secrets protection in pipelines</strong> — Instead of storing credentials in plaintext or in misconfigured vaults, the YubiKey can serve as a root of trust for decrypting data only at execution time. Particularly useful in semi-manual pipelines (controlled deploys, runbooks, emergency operations) where human presence is already expected. In practice, the secret only "exists" in memory for a few seconds and depends on a physical factor to be accessed.</p>
<p><strong>Non-repudiation for compliance</strong> — Each device has a unique identifier, making it possible to tie critical actions — key rotation, production config changes, sensitive data access — to a specific hardware device. This enables stronger auditing: not just "which user did it" but "which physical device was used."</p>
<p><strong>Code signing and supply chain</strong> — GPG or hardware-based signing ensures commits, tags, and artifacts can only be signed with physical presence. This prevents an attacker who compromised a CI environment from forging signed releases — an increasingly relevant problem in supply chain attacks. Same logic applies to container images and internally distributed packages.</p>
<p><strong>Unlock factor for internal tools</strong> — Admin panels, SRE portals, or sensitive CLIs can require FIDO2 authentication before executing destructive operations ("drain cluster", "delete namespace", "rotate CA"). This adds intentional friction exactly where it should exist: on irreversible actions.</p>
<p><strong>Session compromise mitigation</strong> — Even if a machine is invaded or a terminal is open, the absence of the physical device prevents new authentications and critical operations. This limits attack impact and forces the adversary to act within a much more restricted window.</p>
<p><strong>Personal identity anchor</strong> — The same YubiKey can be used for service login, code signing, SSH access, and data decryption. This consolidates identity, reduces attack surface, and simplifies the mental model: instead of dozens of distributed secrets, you have a single strong control point — that conveniently cannot be copied.</p>
<h3>Programming Language Integration</h3>
<h4>Python</h4>
<pre><code class="language-bash">pip install yubikey-manager cryptography fido2
# yubikey-manager exposes the ykman API as a library
</code></pre>
<h4>Go</h4>
<pre><code class="language-bash">go get github.com/go-piv/piv-go/piv
go get golang.org/x/crypto
</code></pre>
<h4>Rust</h4>
<pre><code class="language-toml"># Cargo.toml
[dependencies]
yubikey = { version = "0.8", features = ["untested"] }
age = "0.10"
aes-gcm = "0.10"
rand = "0.8"
sha2 = "0.10"
rsa = { version = "0.9", features = ["sha2"] }
</code></pre>
<p><strong>age + YubiKey (the modern approach):</strong> The <a href="https://github.com/FiloSottile/age">age</a> project is the modern successor to GPG for file encryption. The plugin <code>age-plugin-yubikey</code> integrates natively with PIV:</p>
<pre><code class="language-bash">cargo install age-plugin-yubikey
</code></pre>
<h3>Firmware Updates and Recent Changes</h3>
<p>Yubico published relevant evolutions in the YubiKey 5 line with firmware 5.7: increased credential storage capacity, PIN management improvements, and enterprise-oriented features including enterprise attestation and CTAP 2.1 changes.</p>
<p>One point many people insist on ignoring: <strong>firmware is not user-upgradeable</strong>. If you want new firmware, you buy a new key.</p>
<p>References:</p>
<ul>
<li><p><a href="https://www.yubico.com/blog/now-available-for-purchase-yubikey-5-series-and-security-key-series-with-new-5-7-firmware/">YubiKey 5 Series with 5.7 firmware</a></p>
</li>
<li><p><a href="https://docs.yubico.com/hardware/yubikey/yk-tech-manual/yk5-firmware-overview.html">YubiKey 5 Technical Manual</a></p>
</li>
<li><p><a href="https://docs.yubico.com/hardware/yubikey/yk-tech-manual/5.7-firmware-specifics.html">5.7 Firmware Specifics</a></p>
</li>
</ul>
<h3>What I Consider "Good Use" of YubiKey in 2026</h3>
<p>Good use is what reduces classes of attacks and improves your operations. Not what gives you more <em>feeling</em> of security.</p>
<ul>
<li><p><strong>For web accounts:</strong> Prioritize FIDO2/WebAuthn when available. The security leap is structural — you stop depending on a typeable secret and depend on authentication bound to the correct service.</p>
</li>
<li><p><strong>For local Linux:</strong> If you do things that matter, requiring a token for <code>sudo</code> is one of the best cost/benefit ratios. Not because "nobody will become root," but because you cut the most common path of opportunistic attack.</p>
</li>
<li><p><strong>For SSH:</strong> Hardware-backed auth changes the impact of credential exfiltration. Doesn't cure a compromised endpoint, but reduces the damage from passive leaks and makes identity harder to clone.</p>
</li>
<li><p><strong>For personal/professional encryption:</strong> OpenPGP with subkeys by purpose and smartcard operation is the kind of discipline that prevents workarounds from becoming habits. Here the YubiKey is less "extra security" and more "minimum governance to not self-sabotage."</p>
</li>
</ul>
<p><strong>Non-negotiable rule:</strong> if you use one key, have two. The first is the one you carry. The second is the one that prevents "I lost an object" from becoming "I lost my digital identity."</p>
<p>Backup codes offline continue to exist for a reason.</p>
<h3>Final Considerations</h3>
<p>The YubiKey is not a silver bullet — it's a physical security layer that complements good practices. Points the pragmatic SRE needs to keep in mind:</p>
<ul>
<li><p><strong>Backup:</strong> Always have a second YubiKey configured. Losing your only key is a formative experience you don't want to have.</p>
</li>
<li><p><strong>PIN vs Touch:</strong> Configure <code>touch-policy=always</code> for critical operations. Physical touch is what differentiates the YubiKey from a key file on disk.</p>
</li>
<li><p><strong>Remote forwarding:</strong> For remote servers, <code>usbip</code> allows USB forwarding over the network. Alternative: use SSH agent forwarding with <code>ssh-agent</code> + FIDO2.</p>
</li>
<li><p><strong>Auditing:</strong> The YubiKey serial is unique and can be used as an operator identifier in audit logs.</p>
</li>
<li><p><strong>Revocation:</strong> Have a documented process for revoking and replacing keys when a YubiKey is lost or compromised.</p>
</li>
</ul>
<p>The premise is simple: what's on the hardware cannot be exfiltrated by malware. An attacker who compromised your machine can steal your active session, but cannot open a new SSH connection, decrypt new files, or sign new commits without the physical token. This drastically reduces the exposure window.</p>
<h3>Conclusion</h3>
<p>The series started as 2FA and ended as identity and risk control. If you use YubiKey only to spit out OTP, you're using the most fragile mode of the ecosystem — useful, but far from the best. The value appears when you move authentication to FIDO2/WebAuthn where possible, use the hardware to reduce exfiltration in SSH, and treat cryptography (GPG) as something that deserves separation of functions and operation with less exposure.</p>
<p>This post is a commented index of the series, but also a reminder: security that depends on perfect user discipline is expensive and fails. Security that improves system design is cheaper in the long run and fails less embarrassingly.</p>
<h3>References</h3>
<p><strong>YubiKey Series (Portuguese originals):</strong></p>
<ul>
<li><p><a href="https://esli.blog.br/yubikey-introducao">YubiKey #1 — Introdução ao 2FA</a></p>
</li>
<li><p><a href="https://esli.blog.br/yubikey-linux-instalacao">YubiKey #2 — Linux Instalação</a></p>
</li>
<li><p><a href="https://esli.blog.br/yubikey-console-sudo-ssh">YubiKey #3 — Console, sudo e SSH</a></p>
</li>
<li><p><a href="https://esli.blog.br/yubikey-ssh-ed25519-ecdsa">YubiKey #4 — OpenSSH + ed25519</a></p>
</li>
<li><p><a href="https://esli.blog.br/yubikey-chaves-gpg">YubiKey #5 — Chaves GPG</a></p>
</li>
</ul>
<p><strong>Cryptography (my blog):</strong></p>
<ul>
<li><p><a href="https://esli.blog.br/criptografia-para-iniciantes">Criptografia para iniciantes</a></p>
</li>
<li><p><a href="https://esli.blog.br/ferramentas-para-criptografia">Ferramentas para Criptografia</a></p>
</li>
<li><p><a href="https://esli.blog.br/como-escolher-ferramentas-de-criptografia">Como escolher Ferramentas de Criptografia</a></p>
</li>
<li><p><a href="https://esli.blog.br/o-que-e-o-wireguard">O que é o WireGuard?</a></p>
</li>
</ul>
<p><strong>Official Yubico:</strong></p>
<ul>
<li><p><a href="https://www.yubico.com/blog/now-available-for-purchase-yubikey-5-series-and-security-key-series-with-new-5-7-firmware/">YubiKey 5.7 Firmware Announcement</a></p>
</li>
<li><p><a href="https://docs.yubico.com/hardware/yubikey/yk-tech-manual/yk5-firmware-overview.html">YubiKey 5 Technical Manual</a></p>
</li>
<li><p><a href="https://docs.yubico.com/hardware/yubikey/yk-tech-manual/5.7-firmware-specifics.html">5.7 Firmware Specifics</a></p>
</li>
<li><p><a href="https://www.yubico.com/why-yubico/how-the-yubikey-works/">How the YubiKey Works</a></p>
</li>
<li><p><a href="https://www.yubico.com/br/works-with-yubikey/catalog/?sort=popular">Works with YubiKey Catalog</a></p>
</li>
<li><p><a href="https://developers.yubico.com/PGP/Importing_keys.html">Importing Keys to YubiKey</a></p>
</li>
<li><p><a href="https://developers.yubico.com/">Yubico Developers</a></p>
</li>
</ul>
<p><strong>Libraries and Tools:</strong></p>
<ul>
<li><p><a href="https://github.com/go-piv/piv-go">piv-go (Google)</a></p>
</li>
<li><p><a href="https://github.com/iqlusioninc/yubikey.rs">rust-yubikey (Fortanix)</a></p>
</li>
<li><p><a href="https://github.com/str4d/age-plugin-yubikey">age-plugin-yubikey</a></p>
</li>
<li><p><a href="https://github.com/Yubico/yubikey-manager">yubikey-manager (Python)</a></p>
</li>
<li><p><a href="https://github.com/Yubico/libfido2">libfido2</a></p>
</li>
</ul>
<p><strong>GPG Cheatsheets:</strong></p>
<ul>
<li><p><a href="https://devhints.io/gnupg">devhints.io/gnupg</a></p>
</li>
<li><p><a href="https://blog.programster.org/gpg-cheatsheet">GPG Cheatsheet (programster)</a></p>
</li>
<li><p><a href="https://gock.net/blog/2020/gpg-cheat-sheet/">GPG Cheatsheet (gock.net)</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[YubiKey: compilado (com criptografia, Linux e o que mudou de lá para cá)]]></title><description><![CDATA[Escrevi uma série de artigos sobre YubiKey ao longo dos últimos anos. A ideia original era simples: sair do “2FA por obrigação” e chegar no “2FA/MFA por arquitetura”. No caminho, a chave deixou de ser]]></description><link>https://esli.blog.br/yubikey-compilado-com-criptografia-linux-e-o-que-mudou-de-l-para-c</link><guid isPermaLink="true">https://esli.blog.br/yubikey-compilado-com-criptografia-linux-e-o-que-mudou-de-l-para-c</guid><category><![CDATA[yubikey]]></category><category><![CDATA[yubikeys]]></category><category><![CDATA[ssh]]></category><category><![CDATA[Security]]></category><category><![CDATA[2FA]]></category><category><![CDATA[MFA]]></category><category><![CDATA[Cryptography]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Mon, 06 Apr 2026 04:13:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/354508a5-6d2d-46c8-bebc-b765d295bfba.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Escrevi uma série de artigos sobre YubiKey ao longo dos últimos anos. A ideia original era simples: sair do “2FA por obrigação” e chegar no “2FA/MFA por arquitetura”. No caminho, a chave deixou de ser um penduricalho caro e virou um componente útil de um setup coerente: Linux mais duro, SSH menos dependente de arquivos sensíveis, GPG menos exposto e autenticação mais resistente a phishing.</p>
<p>Este post é um resumo unificado dos artigos anteriores, com links diretos para referência, e com atualizações técnicas que fazem sentido em 2026 — especialmente no eixo FIDO2/WebAuthn, passkeys e políticas de PIN/gestão que evoluíram bastante. Também conecto com outros textos meus sobre criptografia, porque YubiKey é uma consequência prática: você para de falar “cripto” como conceito abstrato e passa a operacionalizar chaves, assinatura, identidade e risco.</p>
<h2>Antes de tudo: YubiKey não é “um 2FA melhorado”</h2>
<p>A tentação é tratar YubiKey como “o mesmo 2FA, só que em USB”. Isso é reduzir o assunto ao pior caso de uso: OTP digitável, dependente do usuário, exposto a phishing e a UXs tortas. O valor real aparece quando você entende que ela suporta múltiplos protocolos e que cada um deles muda o tipo de ataque que você precisa derrotar.</p>
<p>Quando você sai de códigos e entra em FIDO2/WebAuthn, por exemplo, você não está “melhorando 2FA”, você está mudando a categoria: a autenticação fica vinculada ao origin (o site), e isso reduz drasticamente a classe de ataque baseada em páginas falsas e coleta de segredo reutilizável. Quando você leva a chave para SSH, você reduz o impacto do roubo/exfiltração do seu <code>$HOME</code>. Quando leva para OpenPGP, você diminui a exposição do material de chave e melhora sua disciplina de subkeys e finalidades.</p>
<h2>Parte 1 — A série original</h2>
<h3>YubiKey #1 — Introdução ao 2FA</h3>
<p>No primeiro artigo estabeleço o motivo da série existir: senhas vazam, usuários reutilizam, e qualquer mecanismo “extra” que ainda dependa do usuário digitar um segredo é melhor do que nada, mas continua com falhas previsíveis.</p>
<p>A chave física entra como fator de posse para elevar a barra e reduzir o efeito dominó de credenciais comprometidas. O ponto importante ali é o enquadramento: YubiKey não é só um gerador de código. É um autenticador multi-protocolo. Isso muda a conversa de “qual app de token eu uso” para “qual protocolo eu escolho para o meu risco”. Link: <a href="https://esli.blog.br/yubikey-introducao">https://esli.blog.br/yubikey-introducao</a></p>
<h3>YubiKey #2 — Linux instalação: plug-and-play, pcscd e ferramentas</h3>
<p>No segundo artigo trago o contexto do Linux: muitas funções básicas funcionam sem instalar nada porque parte do comportamento pode aparecer como dispositivo HID (teclado) para OTP. Só que a vida real (OATH no Authenticator, PIV, OpenPGP) passa pelo stack de smartcard e ferramentas como o Yubico Authenticator e o YubiKey Manager.</p>
<p>O artigo também faz um inventário do que uma YubiKey 5 NFC suporta e por que isso importa: FIDO U2F/FIDO2, OTP, OATH, PIV, OpenPGP. A consequência prática é clara: antes de “configurar”, você precisa decidir o que vai usar e o que vai desabilitar, porque deixar tudo ligado por padrão costuma ser o jeito mais eficiente de colecionar surpresas. Link: <a href="https://esli.blog.br/yubikey-linux-instalacao">https://esli.blog.br/yubikey-linux-instalacao</a></p>
<h3>YubiKey #3 — Console, sudo e SSH</h3>
<p>O terceiro artigo é onde a YubiKey deixa de ser “2FA de site” e vira controle local de privilégio.</p>
<p>Eu mostro dois caminhos no PAM: um baseado em Yubico OTP (<code>libpam-yubico</code> com API ID/secret e mapeamento de usuários/keys) e outro baseado em U2F (<code>libpam-u2f</code> com <code>pam_u2f</code> e <code>pamu2fcfg</code>).</p>
<p>O resultado prático é endurecer login em console e, principalmente, exigir presença do token para <code>sudo</code>. Isso ataca um cenário comum: a senha do usuário foi obtida (ou a sessão foi “emprestada”), e agora virar root é só uma questão de hábito. Com a chave no fluxo, o atacante precisa também do hardware e do momento. Eu também deixo registrado o detalhe que muita gente ignora: “colocar PAM no SSH” não cria automaticamente um 2FA remoto robusto. Sem desenho de fluxo e parâmetros corretos, você quebra acesso ou cria uma falsa sensação de segurança. Link: <a href="https://esli.blog.br/yubikey-console-sudo-ssh">https://esli.blog.br/yubikey-console-sudo-ssh</a></p>
<h3>YubiKey #4 — OpenSSH + YubiKey (ed25519 e afins)</h3>
<p>No quarto artigo entro no uso para SSH, e isso é uma das melhores aplicações para infraestrutura: reduzir o impacto de exfiltração de chaves privadas e aumentar o custo de ataque local.</p>
<p>A ideia é simples, mas tem implicação profunda: em vez de o host guardar um segredo que te representa, ele guarda um identificador e delega a operação de assinatura para o hardware no momento do login. Na prática, você reduz a “portabilidade acidental” de credenciais. Backups ficam menos perigosos, dotfiles vazados ficam menos catastróficos, e o atacante que conseguir ler seu disco não ganha automaticamente sua identidade SSH. Isso não resolve endpoint comprometido, mas muda o tipo de incidente e o esforço necessário para persistência. Link: <a href="https://esli.blog.br/yubikey-ssh-ed25519-ecdsa">https://esli.blog.br/yubikey-ssh-ed25519-ecdsa</a></p>
<h3>YubiKey #5 — Chaves GPG: subkeys, finalidades e o prazer de parar de improvisar criptografia</h3>
<p>O quinto artigo amarra criptografia aplicada com a chave: geração de chaves RSA e ECC no GnuPG, criação de subkeys, e o uso correto por finalidade. Eu bato em um ponto que vale repetir: uma chave não deveria ser “faz tudo”. Subkeys existem para separar assinatura, criptografia e autenticação; isso melhora segurança e também melhora sua capacidade de operar com disciplina (revogar, rotacionar, isolar).</p>
<p>Além do básico de <code>gpg --gen-key</code> e do fluxo de export/backup, o artigo entra em <code>keytocard</code> para mover material para a YubiKey e operar no modelo de smartcard. O ganho não é “criptografar mais”: é expor menos o material que realmente importa. Link: <a href="https://esli.blog.br/yubikey-chaves-gpg">https://esli.blog.br/yubikey-chaves-gpg</a></p>
<h2>Parte 2 — Onde a criptografia entra (e os meus outros artigos que se conectam com isso)</h2>
<p>YubiKey não substitui criptografia. Ela é uma forma de forçar criptografia a sair do plano do “conceito correto” e entrar no plano do “uso correto”.</p>
<p>Em outras palavras: ela te obriga a pensar em identidade, chaves, finalidades, recuperação e falhas.</p>
<p>Isso conversa diretamente com outros textos meus: Em “Criptografia para iniciantes”, eu explico a base: simétrica vs assimétrica, hash, salt e por que confundir integridade com confidencialidade dá ruim. Esse é o pano de fundo que ajuda a entender por que “um código de 6 dígitos” (TOTP) não é do mesmo universo de uma autenticação vinculada ao origin (FIDO2). Link: <a href="https://esli.blog.br/criptografia-para-iniciantes">https://esli.blog.br/criptografia-para-iniciantes</a></p>
<p>Em “Ferramentas para Criptografia” e “Como escolher Ferramentas de Criptografia”, eu puxo o assunto para o lado pragmático: escolher ferramenta por caso de uso, reduzir fricção, evitar complexidade desnecessária e, principalmente, não usar OpenPGP como martelo universal quando a sua dor é outra. YubiKey entra aqui como “hardening do material de chave”, não como “mais uma ferramenta de cripto”. Links: <a href="https://esli.blog.br/ferramentas-para-criptografia">https://esli.blog.br/ferramentas-para-criptografia</a> e <a href="https://esli.blog.br/como-escolher-ferramentas-de-criptografia">https://esli.blog.br/como-escolher-ferramentas-de-criptografia</a></p>
<p>E em “O que é o WireGuard?”, eu mostro um exemplo de criptografia moderna bem aplicada: algoritmos sólidos, design direto, pouca área para erro humano e operação simples. É a mesma filosofia que justifica trocar 2FA frágil por autenticação resistente a phishing quando o ecossistema permite. Link: <a href="https://esli.blog.br/o-que-e-o-wireguard">https://esli.blog.br/o-que-e-o-wireguard</a></p>
<h2>Parte 3 — Atualizações que importam (FIDO2, passkeys e firmware recente)</h2>
<p>O ecossistema avançou. A palavra da moda virou “passkeys”, mas a parte importante é: FIDO2/WebAuthn é a rota mais curta hoje para reduzir phishing como classe de ataque, e não só “adicionar um segundo passo”.</p>
<p>A Yubico publicou evoluções relevantes na linha YubiKey 5 com firmware 5.7, com aumento de capacidade de armazenamento para credenciais, melhorias de gerenciamento de PIN e recursos voltados a ambientes enterprise, incluindo opções como enterprise attestation e mudanças ligadas a CTAP 2.1. Referência oficial: <a href="https://www.yubico.com/blog/now-available-for-purchase-yubikey-5-series-and-security-key-series-with-new-5-7-firmware/">https://www.yubico.com/blog/now-available-for-purchase-yubikey-5-series-and-security-key-series-with-new-5-7-firmware/</a></p>
<p>Para quem quer detalhe técnico (em vez de marketing), o manual técnico da Yubico documenta matriz de capacidades por versão de firmware e explica recursos e limitações com mais precisão, inclusive deixando explícito um ponto que muita gente insiste em ignorar: firmware não é atualizável pelo usuário; se você quer firmware novo, você compra chave nova. Referência: <a href="https://docs.yubico.com/hardware/yubikey/yk-tech-manual/yk5-firmware-overview.html">https://docs.yubico.com/hardware/yubikey/yk-tech-manual/yk5-firmware-overview.html</a> e detalhes 5.7/5.6 aqui: <a href="https://docs.yubico.com/hardware/yubikey/yk-tech-manual/5.7-firmware-specifics.html">https://docs.yubico.com/hardware/yubikey/yk-tech-manual/5.7-firmware-specifics.html</a></p>
<h2>Parte 4 — O que eu considero “uso bom” de YubiKey em 2026</h2>
<p>O uso bom é aquele que reduz classes de ataque e melhora sua operação. Não é o que te dá mais sensação de segurança.</p>
<p>Para contas web: priorize FIDO2/WebAuthn quando existir. O salto de segurança é estrutural, porque você deixa de depender de segredo digitável e depende de autenticação vinculada ao serviço certo.</p>
<p>Para Linux local: se você faz coisas que importam, exigir token no <code>sudo</code> é uma das melhores relações custo/benefício. Não porque “ninguém vai virar root”, mas porque você corta o caminho mais comum do ataque oportunista.</p>
<p>Para SSH: hardware-backed auth muda o impacto de exfiltração de credenciais. Não cura endpoint comprometido, mas reduz o estrago de vazamento passivo e deixa a identidade mais difícil de clonar.</p>
<p>Para criptografia pessoal/profissional: OpenPGP com subkeys por finalidade e operação via smartcard é o tipo de disciplina que evita gambiarra virar hábito. Aqui a YubiKey é menos “segurança extra” e mais “governança mínima para não se auto-sabotar”.</p>
<p>E a regra que eu trataria como não-negociável: se você usa uma chave, tenha duas. A primeira é a que você carrega. A segunda é a que te impede de transformar “perdi um objeto” em “perdi minha identidade digital”.</p>
<p>Backup codes offline continuam existindo por um motivo.</p>
<h2>Conclusão</h2>
<p>A série começou como 2FA e acabou como identidade e controle de risco. Se você usa YubiKey só para cuspir OTP, você está usando o modo mais frágil do ecossistema — útil, mas longe do melhor. O valor aparece quando você move autenticação para FIDO2/WebAuthn onde der, usa o hardware para reduzir exfiltração em SSH e trata criptografia (GPG) como algo que merece separação de funções e operação com menos exposição.</p>
<p>Este post é um índice comentado da série, mas também um lembrete: segurança que depende de disciplina perfeita do usuário é cara e falha. Segurança que melhora o desenho do sistema é mais barata no longo prazo e falha de forma menos humilhante.</p>
<h2>Referências (série YubiKey)</h2>
<p><a href="https://esli.blog.br/yubikey-introducao">https://esli.blog.br/yubikey-introducao</a></p>
<p><a href="https://esli.blog.br/yubikey-linux-instalacao">https://esli.blog.br/yubikey-linux-instalacao</a></p>
<p><a href="https://esli.blog.br/yubikey-console-sudo-ssh">https://esli.blog.br/yubikey-console-sudo-ssh</a></p>
<p><a href="https://esli.blog.br/yubikey-ssh-ed25519-ecdsa">https://esli.blog.br/yubikey-ssh-ed25519-ecdsa</a></p>
<p><a href="https://esli.blog.br/yubikey-chaves-gpg">https://esli.blog.br/yubikey-chaves-gpg</a></p>
<h2>Referências (criptografia no meu blog)</h2>
<p><a href="https://esli.blog.br/criptografia-para-iniciantes">https://esli.blog.br/criptografia-para-iniciantes</a></p>
<p><a href="https://esli.blog.br/ferramentas-para-criptografia">https://esli.blog.br/ferramentas-para-criptografia</a></p>
<p><a href="https://esli.blog.br/como-escolher-ferramentas-de-criptografia">https://esli.blog.br/como-escolher-ferramentas-de-criptografia</a></p>
<p><a href="https://esli.blog.br/o-que-e-o-wireguard">https://esli.blog.br/o-que-e-o-wireguard</a></p>
<h2>Referências oficiais (Yubico)</h2>
<p><a href="https://www.yubico.com/blog/now-available-for-purchase-yubikey-5-series-and-security-key-series-with-new-5-7-firmware/">https://www.yubico.com/blog/now-available-for-purchase-yubikey-5-series-and-security-key-series-with-new-5-7-firmware/</a></p>
<p><a href="https://docs.yubico.com/hardware/yubikey/yk-tech-manual/yk5-firmware-overview.html">https://docs.yubico.com/hardware/yubikey/yk-tech-manual/yk5-firmware-overview.html</a></p>
<p><a href="https://docs.yubico.com/hardware/yubikey/yk-tech-manual/5.7-firmware-specifics.html">https://docs.yubico.com/hardware/yubikey/yk-tech-manual/5.7-firmware-specifics.html</a></p>
]]></content:encoded></item><item><title><![CDATA[Anatel e o velho sonho de cobrar pedágio da Internet (Tomada de Subsídios 1/2026)]]></title><description><![CDATA[Por que não só cobrar pela velocidade, mas também cobrar pelo tráfego/download? Ah, vamos cobrar também das empresas dos grandes serviços com mais assinaturas e tráfego pelos usuários... É a bitributa]]></description><link>https://esli.blog.br/anatel-e-o-velho-sonho-de-cobrar-ped-gio-da-internet-tomada-de-subs-dios-1-2026</link><guid isPermaLink="true">https://esli.blog.br/anatel-e-o-velho-sonho-de-cobrar-ped-gio-da-internet-tomada-de-subs-dios-1-2026</guid><category><![CDATA[Anatel]]></category><category><![CDATA[taxas]]></category><category><![CDATA[imposto]]></category><category><![CDATA[internet]]></category><category><![CDATA[noticias]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Sun, 05 Apr 2026 19:37:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/3464aeab-f38b-4275-836d-0e60c5052af7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Por que não só cobrar pela velocidade, mas também cobrar pelo tráfego/download? Ah, vamos cobrar também das empresas dos grandes serviços com mais assinaturas e tráfego pelos usuários... É a bitributação ao próximo nível: pagar 2x, 3x para ter a mesma coisa.</p>
<p>Pagar pela velocidade, pagar pelo tráfego/download, pagar a mais nos serviços assinados e... pagar mais ainda porque estou utilizando (escolhi assinar) o serviço XPTO e não o ZYX que a operadora me oferece “de graça" e fora da franquia de dados.</p>
<p>A Anatel abriu a <strong>Tomada de Subsídios nº 1/2026</strong> para juntar informações e montar um possível <strong>regulamento sobre “deveres dos usuários”</strong> — com foco explícito em <strong>“grandes usuários de rede”</strong>, leia-se: <strong>plataformas grandes (streaming, redes sociais, etc.)</strong> e o tráfego que elas geram. Junto disso, entrou um segundo pacote: <strong>como serviços digitais/assinaturas (SVAs)</strong> são empurrados, cobrados e cancelados nos planos das operadoras.</p>
<p>Fontes:</p>
<ul>
<li><p>Notícia: <a href="https://teletime.com.br/30/03/2026/anatel-abre-tomada-de-subsidios-sobre-regulamento-de-grandes-usuarios/">TELETIME (30/03/2026)</a></p>
</li>
<li><p>Texto oficial: <a href="https://apps.anatel.gov.br/ParticipaAnatel/VisualizarTextoConsulta.aspx?TelaDeOrigem=2&amp;ConsultaId=20387">Participa Anatel – Tomada nº 1/2026</a></p>
</li>
<li><p>Nota da Anatel: <a href="https://www.gov.br/anatel/pt-br/assuntos/noticias/anatel-abre-consulta-sobre-deveres-dos-usuarios-e-uso-de-redes-por-gigantes-de-tecnologia">Anatel (</a><a href="http://gov.br">gov.br</a><a href="https://www.gov.br/anatel/pt-br/assuntos/noticias/anatel-abre-consulta-sobre-deveres-dos-usuarios-e-uso-de-redes-por-gigantes-de-tecnologia">)</a></p>
</li>
</ul>
<h4>O que a Anatel está mirando (sem rodeios)</h4>
<ol>
<li><p><strong>A parte “fair share” (pedágio)</strong><br />A pauta é: “plataformas grandes geram muito tráfego; logo, deveriam ajudar a pagar a conta da rede”. A tomada pede dados para sustentar esse tipo de tese: impacto de tráfego, custos, congestionamento, onde o tráfego está (no Brasil ou fora), etc.</p>
</li>
<li><p><strong>A parte das assinaturas empurradas (SVA)</strong><br />Aqui o foco é mais pró-consumidor: consentimento claro, fim de “assinatura fantasma”, cancelamento menos infernal, e responsabilidades quando operadora e parceiro jogam a culpa um no outro.</p>
</li>
</ol>
<p><strong>O que é “assinatura fantasma”</strong><br />É quando você <strong>passa a pagar por uma assinatura/SVA sem perceber direito</strong>, normalmente porque ela foi:</p>
<ul>
<li><p>incluída como “benefício” no plano e depois <strong>começou a cobrar</strong>,</p>
</li>
<li><p>ativada com <strong>1 clique</strong> em fluxo confuso,</p>
</li>
<li><p>liberada como <strong>teste grátis (trial)</strong> e virou cobrança automática,</p>
</li>
<li><p>ou “autorizada” por um <strong>consentimento genérico</strong> (caixa pré-marcada, aceite amplo, tela que mistura várias coisas).</p>
</li>
</ul>
<p>O resultado prático é sempre o mesmo: <strong>o usuário descobre na fatura</strong> (ou no cartão) e, quando tenta cancelar, entra no modo “labirinto”.</p>
<h4>“Isso já foi tentado antes?”</h4>
<p>Sim, é a continuação de uma trilha antiga, com cara de “vamos insistir até colar”:</p>
<ul>
<li><p><a href="https://apps.anatel.gov.br/ParticipaAnatel/VisualizarTextoConsulta.aspx?TelaDeOrigem=2&amp;ConsultaId=10120">Tomada de Subsídios nº 13/2023</a></p>
</li>
<li><p><a href="https://apps.anatel.gov.br/ParticipaAnatel/VisualizarTextoConsulta.aspx?TelaDeOrigem=2&amp;ConsultaId=20202">Tomada de Subsídios nº 26/2024</a></p>
</li>
<li><p>Agora: <a href="https://apps.anatel.gov.br/ParticipaAnatel/VisualizarTextoConsulta.aspx?TelaDeOrigem=2&amp;ConsultaId=20387">Tomada de Subsídios nº 1/2026</a></p>
</li>
</ul>
<p>E tem cobertura extra no mesmo sentido:</p>
<ul>
<li><p><a href="https://telesintese.com.br/com-tomada-de-subsidios-anatel-reabre-debate-sobre-fair-share-no-brasil/">Tele.Síntese</a></p>
</li>
<li><p><a href="https://convergenciadigital.com.br/internet/fair-share-anatel-abre-consulta-para-saber-se-big-techs-tem-de-pagar-teles-pelo-uso-da-rede-e-sobre-direitos-do-usuario/">Convergência Digital</a></p>
</li>
<li><p><a href="https://www.demarest.com.br/tomada-de-subsidios-no-1-2026-anatel-inicia-coleta-de-informacoes-sobre-regulamento-de-deveres-dos-usuarios-e-comercializacao-dos-servicos-de-valor-adicionado/">Demarest</a></p>
</li>
<li><p>Contexto: <a href="https://teletime.com.br/12/03/2026/anatel-fara-nova-tomada-de-subsidio-sobre-regulamento-de-grandes-usuarios/">TELETIME (12/03/2026)</a></p>
</li>
</ul>
<h3>Causas e danos (o que pode acontecer na prática)</h3>
<h4>Para o usuário final (você, eu, a conta no fim do mês)</h4>
<p><strong>Possível ganho real:</strong> menos “serviço extra” que aparece na fatura, menos pegadinha de trial, mais clareza de consentimento e cancelamento.</p>
<p><strong>Possível dano real:</strong> se a parte do “pedágio” avançar, o custo não desaparece por mágica. Ele tende a:</p>
<ul>
<li><p>voltar como <strong>preço maior</strong> (na mensalidade, no streaming, ou nos dois),</p>
</li>
<li><p>ou virar justificativa para <strong>piorar a Internet por categoria de uso</strong> (“este tráfego pesa, então tratemos diferente”).</p>
</li>
</ul>
<h4>Segurança e privacidade</h4>
<p>Para sustentar o discurso de “quem congestiona o quê”, a régua pode escorregar para pedidos de <strong>monitoramento mais detalhado</strong> do uso da rede (mesmo que não falem isso assim). Em termos práticos: mais coleta/relato de dados operacionais e mais tentação de “medir por aplicação”.</p>
<p>Mesmo quando isso não expõe “conteúdo”, metadados e correlações já são suficientes para ampliar risco de:</p>
<ul>
<li><p>vazamento,</p>
</li>
<li><p>uso secundário,</p>
</li>
<li><p>e normalização de vigilância operacional em escala.</p>
</li>
</ul>
<h4>Pequenas empresas e liberdade (onde costuma doer)</h4>
<p>Aqui entra o motivo de lobby e o efeito colateral clássico:</p>
<ul>
<li><p><strong>Operadoras grandes</strong> ganham argumento para criar uma nova fonte de receita (“plataformas paguem”) e para reforçar poder de negociação.</p>
</li>
<li><p><strong>Plataformas grandes</strong> têm dinheiro e jurídico para negociar e cumprir exigências; se virar regra, elas sobrevivem.</p>
</li>
<li><p><strong>Pequenos provedores (ISPs)</strong> e <strong>pequenos serviços digitais</strong> podem acabar com mais burocracia, mais requisitos, mais custo fixo — ou seja, <strong>barreira de entrada</strong> e consolidação de mercado.</p>
</li>
</ul>
<p>Isso não é “liberdade de expressão” no sentido manchete. É a liberdade mais chata e importante: <strong>a de competir e operar sem precisar de um departamento jurídico para existir</strong>.</p>
<h3>Por que tem lobby empurrando isso?</h3>
<p>Porque é uma pauta que promete três coisas que sempre atraem lobby:</p>
<ol>
<li><p><strong>Dinheiro novo</strong> (pedágio sobre tráfego, “contribuição” de plataforma, etc.).</p>
</li>
<li><p><strong>Poder de barganha</strong> (quem controla a rede tenta controlar termos).</p>
</li>
<li><p><strong>Narrativa vendável</strong> (“é justo”, “é para melhorar a qualidade”, “é para proteger o consumidor”).</p>
</li>
</ol>
<p>O pedaço do consumidor (SVA) tem mérito — e justamente por isso pode servir de “cavalo de Troia” para o resto passar com menos resistência.</p>
<h3>Conclusão</h3>
<p>Pensa assim:</p>
<p>Você tem a “<strong>assinatura da airfryer</strong>”: a operadora te vende um combo bonitinho, “leve a airfryer junto”, às vezes com trial, às vezes com um clique, e pronto — de repente você está <strong>pagando a airfryer todo mês</strong> (a tal <strong>assinatura fantasma</strong>), mesmo sem ter pedido de forma clara.</p>
<p>Só que, além disso, você também paga a <strong>conta de luz</strong> normalmente. Ou seja: você já paga pelo serviço essencial (energia) e ainda paga pelo “aparelho/benefício” que veio acoplado.</p>
<p>Aí entra o plot twist regulatório: o governo olha pro sistema e diz:</p>
<blockquote>
<p>“Tem gente usando airfryer demais. Então vamos <strong>cobrar um imposto da fabricante de airfryer</strong> porque os clientes dela estão consumindo muita energia.”</p>
</blockquote>
<p>Na teoria, parece “justo”: quem gera mais uso, paga mais.</p>
<p>Na prática, o que acontece quase sempre é:</p>
<ol>
<li><p>A fabricante repassa o custo no preço da airfryer (ou na “assinatura” dela).</p>
</li>
<li><p>O varejo/operadora repassa de novo no combo.</p>
</li>
<li><p>E o usuário continua pagando a conta de luz do mesmo jeito.</p>
</li>
</ol>
<p>Resultado: você paga <strong>a airfryer</strong>, paga <strong>a energia</strong>, e agora paga também o <strong>imposto “sobre usar energia demais”</strong> — só que embutido no preço final. O custo não some; ele <strong>dá a volta e volta para o consumidor</strong>.</p>
<p>É essa a lógica do lobby do “fair share/pedágio”: vender como “vamos cobrar de quem ‘usa muito’ a rede”, mas no fim vira mais um custo no caminho e com pouca concorrência e muito poder de barganha, <strong>quem fecha a conta é o usuário</strong>.</p>
<p>Outra analogia: A operadora oferece velocidade e limita a 100 Gb de tráfego ao mês. Oferece Deezer de graça e fora da franquia de download. Mas você opta por ter o spotify... Tudo bem, mas pagará mais caro na assinatura, porque o governo taxará o Spotify e a operadora cobrará pedágio dela (do spotify) porque, segundo eles, o Spotify usa muito a infraestrutura deles e há muitos usuários... O Spotify por sua vez, aumenta a assinatura para bancar estes custos.</p>
<p>Se a Anatel quer transformar “grande usuário” em justificativa para <strong>pedágio, monitoramento e diferenciação de tráfego</strong>: o risco é custo maior, mais coleta de dados e um mercado ainda mais fechado onde os grandes negociam, os pequenos só obedecem e o usuário paga uma conta maior.</p>
]]></content:encoded></item><item><title><![CDATA[YubiKey na Programação: Guia Completo para SRE, DevOps e Sysadmin]]></title><description><![CDATA[O que a YubiKey oferece para programadores
Antes de sair escrevendo código, é fundamental entender os protocolos disponíveis no hardware. A YubiKey não é um pendrive de senhas é um HSM (Hardware Secur]]></description><link>https://esli.blog.br/yubikey-na-programa-o-guia-completo-para-sre-devops-e-sysadmin</link><guid isPermaLink="true">https://esli.blog.br/yubikey-na-programa-o-guia-completo-para-sre-devops-e-sysadmin</guid><category><![CDATA[yubikey]]></category><category><![CDATA[yubikeys]]></category><category><![CDATA[SRE]]></category><category><![CDATA[Security]]></category><category><![CDATA[coding]]></category><category><![CDATA[shell script]]></category><category><![CDATA[Bash]]></category><category><![CDATA[encryption]]></category><category><![CDATA[Cryptography]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Sun, 05 Apr 2026 03:33:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/7a4ce7cc-c61e-4be6-9b3b-75b8160dc057.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>O que a YubiKey oferece para programadores</h2>
<p>Antes de sair escrevendo código, é fundamental entender os protocolos disponíveis no hardware. A YubiKey não é um pendrive de senhas é um HSM (Hardware Security Module) de bolso que expõe múltiplas interfaces:</p>
<table>
<thead>
<tr>
<th>Protocolo</th>
<th>Interface</th>
<th>Uso Típico</th>
</tr>
</thead>
<tbody><tr>
<td><strong>OTP (Yubico OTP / HOTP / TOTP)</strong></td>
<td>HID (teclado)</td>
<td>2FA clássico</td>
</tr>
<tr>
<td><strong>FIDO2 / WebAuthn</strong></td>
<td>HID</td>
<td>Login sem senha</td>
</tr>
<tr>
<td><strong>U2F</strong></td>
<td>HID</td>
<td>2FA em apps web</td>
</tr>
<tr>
<td><strong>PIV (Smart Card)</strong></td>
<td>CCID</td>
<td>Criptografia, SSH, certificados</td>
</tr>
<tr>
<td><strong>OpenPGP</strong></td>
<td>CCID</td>
<td>GPG, criptografia de arquivos</td>
</tr>
<tr>
<td><strong>HMAC-SHA1 Challenge-Response</strong></td>
<td>HID</td>
<td>Derivação de chaves, disk encryption</td>
</tr>
<tr>
<td><strong>OATH (TOTP/HOTP)</strong></td>
<td>CCID</td>
<td>Geração de OTPs via app</td>
</tr>
</tbody></table>
<p>Para o contexto de SRE/DevOps, os mais relevantes são: <strong>PIV</strong>, <strong>OpenPGP</strong>, <strong>HMAC-CR</strong> e <strong>FIDO2</strong>.<br />A chave privada nunca sai do chip, o app envia dados para a YubiKey processar; ela devolve o resultado. Isso é o que diferencia um HSM de um arquivo .pem no disco.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/188a8ff4-ad62-48ac-8036-fd288f28c640.png" alt="" style="display:block;margin:0 auto" />

<h2>Shell Script / Bash</h2>
<p>O shell não fala diretamente com a YubiKey, mas os utilitários de linha de comando da Yubico fazem isso muito bem. Para um SRE, isso é suficiente para 80% dos casos de uso.</p>
<p>Dependências:</p>
<pre><code class="language-shell"># Arch
sudo pacman -S yubikey-manager ykpers libfido2 pcsc-tools opensc

# Fedora
sudo dnf install yubikey-manager ykpers libfido2 pcsc-lite opensc

# Verificar se a key está presente
ykman info
</code></pre>
<h3>HMAC-SHA1 Challenge-Response para derivar chave de criptografia</h3>
<p>O slot 2 da YubiKey pode ser configurado para HMAC-CR. Você envia um challenge (até 64 bytes), ela retorna um HMAC de 20 bytes. Isso vira a base de uma chave de criptografia.</p>
<p>encrypt:</p>
<pre><code class="language-shell">#!/usr/bin/env bash
# yk-encrypt.sh — Criptografa arquivo usando YubiKey como fator de chave
set -euo pipefail

FILE="\({1:?Uso: \)0 &lt;arquivo&gt;}"
SLOT=2

# Gera challenge aleatório e salva junto ao arquivo cifrado
CHALLENGE=$(openssl rand -hex 32)
echo "[*] Enviando challenge para YubiKey (slot $SLOT)..."

# ykchalresp retorna o HMAC em hex
HMAC=\((ykchalresp -2 "\)CHALLENGE" 2&gt;/dev/null) || {
    echo "[!] YubiKey não respondeu. Inserida e configurada?" &gt;&amp;2
    exit 1
}

# Deriva chave AES-256 via PBKDF2 (challenge + HMAC como material)
KEY=\((echo -n "\){CHALLENGE}${HMAC}" | openssl dgst -sha256 -binary | xxd -p -c 256)

# Cifra com AES-256-GCM
openssl enc -aes-256-cbc -pbkdf2 -iter 600000 \
    -k "$KEY" \
    -in "$FILE" \
    -out "${FILE}.yk.enc"

# Salva o challenge (sem o HMAC — sem a key física, não abre)
echo "\(CHALLENGE" &gt; "\){FILE}.yk.challenge"

echo "[+] Arquivo cifrado: ${FILE}.yk.enc"
echo "[+] Challenge salvo: ${FILE}.yk.challenge"
echo "[!] Sem a YubiKey, o arquivo não pode ser decifrado."
</code></pre>
<p>E depois, decrypt:</p>
<pre><code class="language-shell">#!/usr/bin/env bash
# yk-decrypt.sh
set -euo pipefail

ENC_FILE="\({1:?Uso: \)0 &lt;arquivo.yk.enc&gt;}"
CHALLENGE_FILE="${ENC_FILE%.enc}.challenge"
SLOT=2

CHALLENGE=\((cat "\)CHALLENGE_FILE")
echo "[*] Aguardando YubiKey..."
HMAC=\((ykchalresp -2 "\)CHALLENGE" 2&gt;/dev/null) || { echo "[!] Falha na YubiKey" &gt;&amp;2; exit 1; }

KEY=\((echo -n "\){CHALLENGE}${HMAC}" | openssl dgst -sha256 -binary | xxd -p -c 256)

openssl enc -d -aes-256-cbc -pbkdf2 -iter 600000 \
    -k "$KEY" \
    -in "$ENC_FILE" \
    -out "${ENC_FILE%.yk.enc}.decrypted"

echo "[+] Decifrado: ${ENC_FILE%.yk.enc}.decrypted"
</code></pre>
<h3>SSH com YubiKey (PIV ou FIDO2)</h3>
<pre><code class="language-shell"># Gera chave FIDO2 residente na YubiKey para SSH
ssh-keygen -t ed25519-sk -O resident -O verify-required \
    -C "esli@infra-prod" -f ~/.ssh/id_ed25519_yk

# A chave privada fica no hardware. O arquivo local é só um "handle".
# Para usar em outro host sem o arquivo:
ssh-keygen -K  # exporta handles das chaves residentes

# Adiciona ao ssh-agent com confirmação de toque obrigatória
ssh-add -K ~/.ssh/id_ed25519_yk
</code></pre>
<h3>GPG com YubiKey para criptografia de arquivos/secrets</h3>
<pre><code class="language-shell"># Verifica se a YubiKey está como cartão GPG
gpg --card-status

# Cifra arquivo para sua própria chave (que está na YubiKey)
gpg --encrypt --recipient esli@esli.blog.br segredo.txt

# Decifra — YubiKey faz a operação, exige PIN
gpg --decrypt segredo.txt.gpg &gt; segredo.txt

# Uso prático: secrets em repositório Git
echo "DB_PASSWORD=hunter2" | gpg --encrypt -r esli@esli.blog.br --armor &gt; .secrets.gpg
# No deploy:
gpg --decrypt .secrets.gpg | source /dev/stdin
</code></pre>
<h2>Python</h2>
<p>Python tem bindings maduros para praticamente tudo relacionado à YubiKey.</p>
<pre><code class="language-shell">pip install yubikey-manager cryptography fido2
# yubikey-manager expõe a API do ykman como biblioteca
</code></pre>
<h2>Go</h2>
<p>Go é a linguagem de eleição para ferramentas de infraestrutura. O pacote <code>piv-go</code> da Google é o estado da arte para PIV.</p>
<pre><code class="language-shell">go get github.com/go-piv/piv-go/piv
go get golang.org/x/crypto
</code></pre>
<h2>Rust</h2>
<p>Rust tem o ecossistema mais completo e seguro para trabalhar com YubiKey. O crate <code>yubikey</code> é mantido ativamente e cobre PIV completamente.</p>
<p>Dependências (cargo.toml):</p>
<pre><code class="language-shell">[dependencies]
yubikey = { version = "0.8", features = ["untested"] }
age = "0.10"
aes-gcm = "0.10"
rand = "0.8"
sha2 = "0.10"
rsa = { version = "0.9", features = ["sha2"] }
</code></pre>
<h3><code>age</code> + YubiKey (a forma moderna)</h3>
<p>O projeto <code>age</code> é o sucessor moderno do GPG para criptografia de arquivos. O plugin <code>age-plugin-yubikey</code> integra nativamente com PIV</p>
<p><code>cargo install age-plugin-yubikey</code></p>
<h2>Aplicações reais da YubiKey no dia a dia de SRE/DevOps</h2>
<p>No mundo real, YubiKey deixa de ser “mais um fator de autenticação” e vira um ponto de controle físico sobre ações críticas. Em ambientes de infraestrutura, isso muda completamente o modelo de ameaça: não basta comprometer credenciais — o atacante precisa também do dispositivo físico.</p>
<p>Um uso direto e frequente é na proteção de acessos privilegiados via SSH. Em vez de depender de chaves privadas armazenadas no filesystem (mesmo com permissões corretas), a autenticação passa a exigir presença física e interação do operador. Isso elimina uma classe inteira de ataques baseada em exfiltração de chave (ex: malware, backup comprometido, vazamento de home directory). Em ambientes com bastion hosts ou acesso a clusters Kubernetes sensíveis, isso reduz drasticamente o risco de movimento lateral silencioso.</p>
<p>Outro cenário recorrente é a proteção de secrets em pipelines e automações. Em vez de armazenar credenciais em texto claro ou mesmo em vaults mal configurados, a YubiKey pode ser utilizada como raiz de confiança para descriptografar dados apenas no momento da execução. Isso é particularmente útil em pipelines semi-manuais (deploys controlados, runbooks, operações de emergência), onde a presença humana já é esperada. Na prática, você cria um modelo onde o segredo só “existe” em memória durante alguns segundos e depende de um fator físico para ser acessado.</p>
<p>Em times que lidam com compliance (financeiro, saúde, governo), a YubiKey também entra como mecanismo de <strong>não repúdio operacional</strong>. Como cada dispositivo possui um identificador único, é possível atrelar ações críticas — como rotação de chaves, alteração de configuração em produção ou acesso a dados sensíveis — a um hardware específico. Isso permite auditoria mais forte: não apenas “qual usuário fez”, mas “qual dispositivo físico foi utilizado”. Em incidentes, isso reduz ambiguidades.</p>
<p>Para proteção de código e supply chain, o uso com GPG ou assinatura baseada em hardware garante que commit, tags e artefatos só possam ser assinados com presença física. Isso impede que um atacante que comprometeu um ambiente CI consiga forjar releases assinadas, um problema cada vez mais relevante em ataques à cadeia de suprimentos. O mesmo raciocínio se aplica a imagens de contêiner e pacotes distribuídos internamente.</p>
<p>Outro caso prático é o uso como fator de desbloqueio para ferramentas internas. Painéis administrativos, portais de SRE, ou até CLIs sensíveis podem exigir autenticação via FIDO2 antes de executar operações destrutivas (ex: “drain cluster”, “delete namespace”, “rotate CA”). Isso adiciona um “atrito intencional” exatamente onde ele deve existir: nas ações irreversíveis. Não é sobre dificultar o trabalho — é sobre impedir erros ou abusos silenciosos.</p>
<p>Em ambientes distribuídos ou com acesso remoto, a YubiKey também atua como mitigação contra comprometimento de sessão. Mesmo que uma máquina seja invadida ou um terminal esteja aberto, a ausência do dispositivo físico impede novas autenticações e operações críticas. Isso limita o impacto de ataques e força o adversário a agir dentro de uma janela muito mais restrita.</p>
<p>Por fim, há o uso como âncora de identidade pessoal no ecossistema técnico. A mesma YubiKey pode ser utilizada para login em serviços, assinatura de código, acesso SSH e descriptografia de dados. Isso consolida identidade, reduz superfície de ataque e simplifica o modelo mental: em vez de dezenas de segredos distribuídos, você tem um único ponto de controle forte — que, convenientemente, não pode ser copiado.</p>
<h2>Referência Rápida: Qual Protocolo Usar?</h2>
<table>
<thead>
<tr>
<th>Necessidade</th>
<th>Protocolo</th>
<th>Ferramenta/Lib</th>
</tr>
</thead>
<tbody><tr>
<td>Criptografia de arquivos</td>
<td>PIV (RSA/ECDH) ou OpenPGP</td>
<td><code>age-plugin-yubikey</code>, <code>gpg</code>, <code>piv-go</code>, <code>yubikey</code> (Rust)</td>
</tr>
<tr>
<td>SSH sem senha</td>
<td>FIDO2 (ed25519-sk)</td>
<td><code>ssh-keygen -t ed25519-sk</code></td>
</tr>
<tr>
<td>2FA em app web</td>
<td>FIDO2/WebAuthn</td>
<td><code>fido2</code> (Python), <code>webauthn</code> (Go/Rust)</td>
</tr>
<tr>
<td>Derivação de chave (disk, vault)</td>
<td>HMAC-SHA1 CR</td>
<td><code>ykchalresp</code>, <code>libykpers</code>, <code>yubikey-manager</code></td>
</tr>
<tr>
<td>Assinatura de código/commits</td>
<td>OpenPGP</td>
<td><code>gpg --card-status</code></td>
</tr>
<tr>
<td>Autenticação em sistemas legados</td>
<td>OTP (HOTP/TOTP)</td>
<td><code>ykman oath</code></td>
</tr>
<tr>
<td>Acesso privilegiado com PIN</td>
<td>PIV</td>
<td><code>piv-go</code>, <code>yubikey</code> (Rust), <code>opensc</code></td>
</tr>
</tbody></table>
<p>Considerações Finais</p>
<p>A YubiKey não é bala de prata, é uma camada de segurança física que complementa boas práticas. Alguns pontos que o SRE pragmático precisa ter em mente:</p>
<p>Backup: Sempre tenha uma segunda YubiKey configurada. Perder a única key é uma experiência formativa que você não quer ter.</p>
<p>PIN vs Touch: Configure <code>touch-policy=always</code> para operações críticas. O toque físico é o que diferencia a YubiKey de um arquivo de chave no disco.</p>
<p>Forwarding remoto: Para servidores remotos, usbip permite forwarding de USB via rede. Alternativa: use o SSH agent forwarding com ssh-agent + FIDO2.</p>
<p>Auditoria: O serial da YubiKey é único e pode ser utilizado como identificador de operador em logs de auditoria.</p>
<p>Revogação: Tenha um processo documentado para revogar e substituir chaves quando uma YubiKey for perdida ou comprometida.</p>
<p>A premissa é simples: o que está no hardware não pode ser exfiltrado por malware. Um atacante que comprometeu sua máquina pode roubar sua sessão ativa, mas não pode abrir uma nova conexão SSH, decifrar novos arquivos ou assinar novos commits sem o token físico. Isso reduz drasticamente a janela de exposição.</p>
<p><em>Referências:</em></p>
<ul>
<li><p><a href="https://developers.yubico.com/">Yubico Developers</a></p>
</li>
<li><p><a href="https://github.com/go-piv/piv-go">piv-go (Google)</a></p>
</li>
<li><p><a href="https://github.com/iqlusioninc/yubikey.rs">rust-yubikey (Fortanix)</a></p>
</li>
<li><p><a href="https://github.com/str4d/age-plugin-yubikey">age-plugin-yubikey</a></p>
</li>
<li><p><a href="https://github.com/Yubico/yubikey-manager">yubikey-manager (Python)</a></p>
</li>
<li><p><a href="https://github.com/Yubico/libfido2">libfido2</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Browser Waterfox irá integrar o bloqueador nativo do Brave]]></title><description><![CDATA[A privacidade na web deixou de ser um "nicho" para se tornar o campo de batalha principal dos navegadores modernos. Brave, Mullvad, Tor foram faíscas nesta guerra.
Recentemente, o Waterfox anunciou um]]></description><link>https://esli.blog.br/browser-waterfox-ir-integrar-o-bloqueador-nativo-do-brave</link><guid isPermaLink="true">https://esli.blog.br/browser-waterfox-ir-integrar-o-bloqueador-nativo-do-brave</guid><category><![CDATA[Brave]]></category><category><![CDATA[adblock]]></category><category><![CDATA[adblocker]]></category><category><![CDATA[waterfox]]></category><category><![CDATA[Browsers]]></category><category><![CDATA[browser]]></category><category><![CDATA[Rust]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Sat, 04 Apr 2026 03:10:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/1aedcfe0-247e-4934-b10a-15f47f31e254.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A privacidade na web deixou de ser um "nicho" para se tornar o campo de batalha principal dos navegadores modernos. Brave, Mullvad, Tor foram faíscas nesta guerra.</p>
<p>Recentemente, o <strong>Waterfox</strong> anunciou uma mudança estrutural que merece nossa atenção técnica: a integração do motor de bloqueio de anúncios do <strong>Brave</strong>, o projeto open source <a href="https://github.com/brave/adblock-rust"><code>adblock-rust</code></a>.</p>
<p>Esta decisão, detalhada no anúncio de <a href="https://www.waterfox.com/blog/15-years-of-forking/">15 anos do blog oficial do Waterfox</a> é uma escolha de engenharia que envolve performance, segurança de memória com Rust e a complexa economia de manter um browser independente hoje.</p>
<h3>O Anúncio: Tradução e Contexto</h3>
<p>No post oficial, Alex Kontos (criador do Waterfox) confirmou que o navegador entregará ainda este ano um <strong>bloqueador de conteúdo nativo</strong>. A escolha pelo motor do Brave foi pautada em três pilares:</p>
<ol>
<li><p><strong>Maturidade Técnica:</strong> O motor já processa bilhões de requisições diariamente nos milhões de instalações do Brave.</p>
</li>
<li><p><strong>Manutenção Profissional:</strong> Uma equipe dedicada mantém as regras de parsing e segurança atualizadas.</p>
</li>
<li><p><strong>Licenciamento:</strong> O <code>adblock-rust</code> usa a licença <strong>MPL-2.0</strong>, compatível com a base de código do Waterfox. Isso evita os conflitos de licença (como a GPLv3 do uBlock Origin) que dificultariam uma integração profunda diretamente no "core" do executável.</p>
</li>
</ol>
<p><strong>Nota importante sobre monetização:</strong> O Waterfox manterá a exibição de anúncios de texto apenas em seu parceiro de busca (Startpage) por questões de sustentabilidade financeira. É crucial notar que esta é uma configuração do Waterfox e não uma limitação do motor do Brave.</p>
<h3>Mergulho Técnico: O que é o <code>adblock-rust</code>?</h3>
<p>Desenvolvido pelo Brave, o <a href="https://github.com/brave/adblock-rust"><code>adblock-rust</code></a> é uma biblioteca de alto desempenho projetada para ser embutida. Ao contrário de extensões que rodam em camadas superiores, este motor permite:</p>
<ul>
<li><p><strong>Bloqueio ao nível de rede:</strong> Interceptação de requisições antes mesmo do processamento pesado.</p>
</li>
<li><p><strong>Filtros Cosméticos e Injeção de Scripts:</strong> Limpeza do DOM para remover espaços vazios de anúncios.</p>
</li>
<li><p><strong>Suporte a Sintaxe de Redes Sociais:</strong> Compatibilidade com listas famosas (EasyList, uBlock, etc.).</p>
</li>
<li><p><strong>Segurança de Memória:</strong> Sendo escrito em <strong>Rust</strong>, ele elimina classes inteiras de bugs de memória que costumam afligir motores escritos em C++.</p>
</li>
</ul>
<h3>Por que Rust?</h3>
<p>A escolha da linguagem Rust para este componente não é moda. No contexto de um navegador, o motor de adblock precisa processar milhares de strings e regras de regex em milissegundos. Rust oferece a performance do "metal" (C/C++) com a garantia de que não ter <em>buffer overflows</em> ou vazamentos de memória críticos durante o parsing de listas de filtros malformadas.</p>
<h3>Conheça os Projetos</h3>
<h4>Waterfox: A Resistência do Gecko</h4>
<p>O <a href="https://www.waterfox.com/">Waterfox</a> é um dos forks mais antigos e respeitados do ecossistema Firefox. Focado em usuários avançados, ele remove telemetria agressiva, experimentos desnecessários da Mozilla e foca na "vibe" original do browser como ferramenta de produtividade, não como hub de anúncios.</p>
<h4>Brave: Inovação em Adblocking</h4>
<p>O <a href="https://brave.com/">Brave</a> revolucionou ao trazer o bloqueio de anúncios para o centro do binário do navegador. Seu motor em Rust agora se torna uma tecnologia "standard" que beneficia outros players menores, fortalecendo o ecossistema de browsers baseados em privacidade.</p>
<h3>Minha Visão Técnica: O Futuro dos Browsers</h3>
<p>Vejo esse movimento como um sinal de amadurecimento do software livre. Navegadores independentes como o Waterfox enfrentam pressões gigantescas (técnicas e financeiras). Em vez de tentar "reinventar a roda" criando um adblocker do zero, Alex Kontos optou por integrar o que há de melhor no mercado via código aberto.</p>
<p>Olhando projetos como o Laybird Browser e o Orion Browser... ambos não são forks de Chrome ou Firefox, Ladybird ainda não teve um stable release e o último (Orion) aceita extensões tanto da Chrome Store quanto do Firefox. Mullvad Browser entrega o nível máximo de segurança sem a rede Tor, que por sua vez está embutida tanto no Brave quanto no Tor Browser.</p>
<p>Cada um acima oferece características únicas, mas o restante não deveria ocupar o tempo dos desenvolvedores reinventando a roda ou criando forks/ports de projetos já maduros.</p>
<p>Integrar o bloqueador dentro do processo principal reduz a latência e o overhead de memória que costumamos ver em extensões WebExtension. Para o usuário final, isso significa uma navegação mais fluida e um navegador que "pesa menos" no sistema, e o adblock-rs do Brave implementa da melhor forma.</p>
<p>A web está mudando, e o Waterfox, ao se aliar tecnicamente ao motor do Brave e à robustez do Rust, garante que continuará sendo uma opção viável para quem não quer ser apenas mais um dado estatístico no Chrome ou no Safari.</p>
<p>Quando um navegador como o Waterfox decide incorporar o <code>adblock-rust</code> do Brave, o que vemos não é apenas uma melhoria de recurso. Vemos um retrato bastante honesto do estado atual da web:</p>
<ul>
<li><p>navegadores independentes estão pressionados financeiramente;</p>
</li>
<li><p>extensões já não são resposta suficiente para tudo;</p>
</li>
<li><p>Rust se consolida como linguagem para componentes críticos;</p>
</li>
<li><p>o open source continua sendo a infraestrutura invisível que permite inovação real.</p>
</li>
</ul>
<p>O anúncio do Waterfox é, ao mesmo tempo, uma boa notícia técnica e um lembrete político. A web aberta ainda depende de projetos independentes, mas manter esses projetos vivos continua sendo um problema tão difícil quanto escrever e manter um bom código.</p>
<h4>Fontes</h4>
<ul>
<li><p><a href="https://www.waterfox.com/blog/15-years-of-forking/">Waterfox Blog — 15 Years of Forking</a></p>
</li>
<li><p><a href="https://github.com/brave/adblock-rust">Brave — adblock-rust no GitHub</a></p>
</li>
<li><p><a href="https://www.waterfox.com/">Waterfox — site oficial</a></p>
</li>
<li><p><a href="https://cyberinsider.com/waterfox-browser-to-add-braves-adblock-engine-allow-search-ads-for-revenue/">CyberInsider — repercussão da notícia</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[NTS: por que você precisa autenticar a hora do seu Linux]]></title><description><![CDATA[O relógio do seu sistema está errado, mas não necessariamente errado no sentido de mostrar a hora errada. Errado no sentido de que qualquer um na rede pode fazer ele mostrar a hora errada, e você não ]]></description><link>https://esli.blog.br/nts-por-que-voc-precisa-autenticar-a-hora-do-seu-linux</link><guid isPermaLink="true">https://esli.blog.br/nts-por-que-voc-precisa-autenticar-a-hora-do-seu-linux</guid><category><![CDATA[TLS]]></category><category><![CDATA[NTP ]]></category><category><![CDATA[nts]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Security]]></category><category><![CDATA[privacy]]></category><category><![CDATA[hacking]]></category><category><![CDATA[TCP]]></category><category><![CDATA[UDP]]></category><category><![CDATA[ntpsec]]></category><category><![CDATA[#Chrony]]></category><category><![CDATA[time]]></category><category><![CDATA[ntppool]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Fri, 03 Apr 2026 18:22:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/0a2492c5-fbc7-423c-a079-a701e3036650.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>O relógio do seu sistema está errado, mas não necessariamente errado no sentido de mostrar a hora errada. Errado no sentido de que qualquer um na rede pode fazer ele mostrar a hora errada, e você não tem como saber.</p>
<p>O protocolo NTP (Network Time Protocol) foi projetado nos anos 1980. Funciona sobre UDP, na porta 123, sem criptografia e sem autenticação. Seu sistema operacional confia cegamente na resposta de um servidor NTP para sincronizar o relógio. E essa confiança cega é explorável.</p>
<p>Se você leu os artigos sobre <a href="https://esli.blog.br/dnscrypt-dns-stamps-e-dns-criptografado-o-guia-que-faltava">DNSCrypt</a>, sobre <a href="https://esli.blog.br/nao-confie-no-seu-provedor-de-internet">não confiar no seu provedor de internet</a> e sobre o <a href="https://esli.blog.br/sni-leak-o-calcanhar-de-aquiles-do-dns-seguro">vazamento via SNI</a>, já percebeu o padrão: protocolos antigos que nunca foram projetados com segurança em mente continuam sendo a fundação da internet moderna. O NTP é mais um deles.</p>
<p>A hora correta é dependência direta de:</p>
<p><strong>Certificados TLS/SSL.</strong> Cada certificado tem campos <code>Not Before</code> e <code>Not After</code>. Se o relógio do cliente estiver fora dessa janela, o certificado é rejeitado (ou aceito indevidamente se o relógio for manipulado para um período em que um certificado revogado ainda era válido).</p>
<p><strong>Kerberos.</strong> O protocolo Kerberos, usado em autenticação corporativa e Active Directory, tem tolerância padrão de 5 minutos. Shift de tempo superior a isso invalida tickets e impede autenticação.</p>
<p><strong>DNSSEC.</strong> Assinaturas DNSSEC têm validade temporal. Um atacante que empurra o relógio de um resolver DNS para frente faz todas as assinaturas DNSSEC expirarem, causando falha na validação e perda de resolução DNS para domínios protegidos.</p>
<p><strong>TOTP/2FA.</strong> Tokens temporais (Google Authenticator, Authy, etc.) dependem de sincronização de tempo. Relógio deslocado significa código errado, que significa login negado.</p>
<p><strong>Logs forenses.</strong> Correlação de eventos entre sistemas depende de timestamps confiáveis. Sem isso, investigação de incidentes e compliance viram exercício de ficção.</p>
<p><strong>RPKI e BGP.</strong> Route Origin Authorizations têm manifests com timestamp. Manipulação de tempo pode fazer um relying party aceitar manifests expirados ou rejeitar válidos, afetando roteamento BGP inteiro.</p>
<p><strong>Cron jobs e schedulers.</strong> Tarefas agendadas executam baseadas no relógio do sistema. Um shift de tempo pode disparar jobs prematuramente, atrasá-los, ou causar loops de execução.</p>
<h2>Os ataques</h2>
<p>Pesquisadores da Boston University publicaram em 2015/2016 o paper "Attacking the Network Time Protocol", documentando ataques práticos contra o NTP. Não são teóricos e foram demonstrados em laboratório e alguns explorados "in the wild".</p>
<h3>On-path: time-shifting</h3>
<p>Um atacante posicionado entre o cliente e o servidor NTP (ISP, rede corporativa, Wi-Fi público) pode modificar as respostas NTP.</p>
<p>O NTP padrão (ntpd) aceita ajustes de até 1000 segundos (panic threshold) sem questionar. E na inicialização, com a flag <code>-g</code> (padrão em muitas distros Linux), aceita qualquer shift, incluindo anos para frente ou para trás.</p>
<p>O ataque "small-step-big-step" funciona assim: o atacante envia shifts pequenos (abaixo do threshold de detecção) durante operação normal. Quando o cliente reinicia, um shift grande é aceito porque o <code>-g</code> permite qualquer correção na inicialização. Resultado: o relógio é deslocado horas ou anos sem gerar alerta.</p>
<h3>Off-path: Kiss-o'-Death (KoD)</h3>
<p>O NTP tem um mecanismo de rate-limiting chamado Kiss-o'-Death (KoD). Quando um cliente envia queries demais, o servidor responde com um pacote KoD mandando o cliente parar.</p>
<p>O problema: em versões anteriores ao ntpd 4.2.8p4, um atacante off-path (sem estar na rota do tráfego) podia spoofar pacotes KoD de cada servidor configurado no cliente.</p>
<p>Resultado: o cliente para de sincronizar e o relógio começa a derivar. Com uma máquina e um scanner de rede, era possível desabilitar NTP em massa pela internet.</p>
<h3>Amplificação DDoS</h3>
<p>O comando <code>monlist</code> do NTP responde com até 600 entradas de clientes recentes. Uma requisição de ~40 bytes gera respostas de ~22KB, fator de amplificação de 556x. Esse ataque foi usado em DDoS massivos em 2014.</p>
<p>O <code>monlist</code> foi desativado em versões recentes, mas servidores NTP antigos e mal configurados continuam disponíveis.</p>
<h3>Cenário prático: forçar aceitação de certificado revogado</h3>
<p>O atacante manipula o NTP para empurrar o relógio do cliente para trás, para um período em que um certificado (já revogado) ainda era válido. O navegador ou aplicação aceita o certificado como legítimo. O atacante faz MITM com o certificado comprometido. A vítima não vê aviso nenhum.</p>
<p>Variante: empurrar o relógio para frente, forçando expiração de certificados DNSSEC. O resolver DNS passa a falhar na validação e o atacante pode então servir respostas DNS falsas sem o DNSSEC bloquear.</p>
<h2>NTS: a solução</h2>
<p>NTS (Network Time Security) é a resposta, padronizado pela RFC 8915 (setembro de 2020). Ele adiciona autenticação criptográfica ao NTP sem alterar o protocolo de medição de tempo em si.</p>
<h3>Como funciona</h3>
<p>O NTS opera em duas fases:</p>
<p><strong>Fase 1: NTS-KE (Key Establishment).</strong> O cliente abre uma conexão TLS (porta TCP 4460) com o servidor NTS. Através desse canal criptografado, cliente e servidor negociam parâmetros de criptografia e o servidor emite cookies (opacos para o cliente). Essa etapa usa TLS 1.3 padrão com verificação de certificado.</p>
<p><strong>Fase 2: NTP autenticado.</strong> As queries NTP subsequentes (UDP 123, como sempre) incluem extensões criptográficas. Cada pacote carrega um cookie e um campo de autenticação (AEAD, geralmente AES-SIV-CMAC-256). O servidor valida o cookie e a autenticação antes de responder. Um pacote NTP adulterado em trânsito falha na verificação e é descartado.</p>
<p>O ponto importante: o NTS não adiciona latência à medição de tempo. O handshake TLS (NTS-KE) ocorre na inicialização e depois aproximadamente uma vez por hora para renovação de cookies. As queries NTP regulares continuam sendo UDP com overhead mínimo (os campos de autenticação).</p>
<p>O servidor não mantém estado por cliente. Os cookies são auto-contidos (criptografados com a chave do servidor). Isso permite escalar para milhões de clientes sem overhead de memória.</p>
<h2>Cenário atual: quem suporta NTS</h2>
<p>Em 2026, existem entre 60 e 70 servidores NTS públicos no mundo. A Europa concentra a maioria, com a Netnod (Suécia) operando 12+ servidores e o PTB (Alemanha) com 4 servidores. A Cloudflare oferece NTS via anycast global. Não existe pool NTS (tipo pool.ntp.org) por causa da dependência de certificados TLS individuais por servidor. Um projeto financiado pelo ICANN (2025-2027), executado pela Trifecta Tech Foundation, trabalha numa solução de pooling para NTS.</p>
<h3>Clientes que suportam NTS</h3>
<table>
<thead>
<tr>
<th>Software</th>
<th>Suporte NTS</th>
<th>Linguagem</th>
<th>Observação</th>
</tr>
</thead>
<tbody><tr>
<td>chrony 4.0+</td>
<td>Sim</td>
<td>C</td>
<td>Padrão no Fedora, RHEL, SUSE, Ubuntu 25.10+</td>
</tr>
<tr>
<td>NTPsec</td>
<td>Sim</td>
<td>C/Python</td>
<td>Fork seguro do ntpd clássico</td>
</tr>
<tr>
<td>ntpd-rs</td>
<td>Sim</td>
<td>Rust</td>
<td>Financiado pela ISRG/Prossimo</td>
</tr>
<tr>
<td>ntpd clássico</td>
<td>Não</td>
<td>C</td>
<td>Legado, não suporta NTS</td>
</tr>
<tr>
<td>systemd-timesyncd</td>
<td>Não</td>
<td>C</td>
<td>Não suporta NTS</td>
</tr>
<tr>
<td>W32Time (Windows)</td>
<td>Não</td>
<td>-</td>
<td>Não suporta NTS</td>
</tr>
</tbody></table>
<p>O chrony é a escolha óbvia para Linux. Já é padrão na maioria das distros que importam (Fedora, RHEL, Arch, SUSE) e o Ubuntu 25.10 adotou chrony com NTS habilitado por padrão em novas instalações.</p>
<h3>Servidores NTS públicos confiáveis</h3>
<table>
<thead>
<tr>
<th>Servidor</th>
<th>Stratum</th>
<th>Localização</th>
<th>Operador</th>
</tr>
</thead>
<tbody><tr>
<td>time.cloudflare.com</td>
<td>3</td>
<td>Anycast global</td>
<td>Cloudflare</td>
</tr>
<tr>
<td>nts.netnod.se</td>
<td>1</td>
<td>Suécia (anycast)</td>
<td>Netnod</td>
</tr>
<tr>
<td>sth1.nts.netnod.se</td>
<td>1</td>
<td>Estocolmo</td>
<td>Netnod</td>
</tr>
<tr>
<td>sth2.nts.netnod.se</td>
<td>1</td>
<td>Estocolmo</td>
<td>Netnod</td>
</tr>
<tr>
<td>ptbtime1.ptb.de</td>
<td>1</td>
<td>Alemanha</td>
<td>PTB (instituto de metrologia)</td>
</tr>
<tr>
<td>ptbtime2.ptb.de</td>
<td>1</td>
<td>Alemanha</td>
<td>PTB</td>
</tr>
<tr>
<td>ptbtime3.ptb.de</td>
<td>1</td>
<td>Alemanha</td>
<td>PTB</td>
</tr>
<tr>
<td>ptbtime4.ptb.de</td>
<td>1</td>
<td>Alemanha</td>
<td>PTB</td>
</tr>
<tr>
<td>ntppool1.time.nl</td>
<td>1</td>
<td>Holanda</td>
<td>TimeNL</td>
</tr>
<tr>
<td>ntppool2.time.nl</td>
<td>1</td>
<td>Holanda</td>
<td>TimeNL</td>
</tr>
<tr>
<td>ntp-pool.rdem-systems.com</td>
<td>2</td>
<td>França</td>
<td>RDEM Systems</td>
</tr>
</tbody></table>
<p>A lista completa e atualizada é mantida em <a href="https://github.com/jauderho/nts-servers">https://github.com/jauderho/nts-servers</a></p>
<p><strong>Sobre a escolha de servidores:</strong> é recomendável usar pelo menos 5 servidores NTS diferentes. Isso protege contra (n-1)/2 falsetickers (servidores que reportam hora incorreta). O chrony aplica algoritmos de consenso entre as fontes para descartar outliers.</p>
<p>Para o Brasil, <code>time.cloudflare.com</code> é a melhor opção de latência por utilizar anycast.</p>
<p>Os servidores europeus (Netnod, PTB) adicionam ~150-200ms de RTT, mas para sincronização NTP isso é perfeitamente aceitável. Não existe servidor NTS público operando na América do Sul no momento. Se você tem infraestrutura e quer contribuir, o repo do jauderho aceita PRs.</p>
<h2>Configuração no Linux</h2>
<h3>Arch / EndeavourOS / Omarchy</h3>
<p>Chrony já vem com suporte NTS compilado. No Arch é o pacote padrão para sincronização de tempo.</p>
<pre><code class="language-bash">sudo pacman -S chrony
</code></pre>
<p>Edite <code>/etc/chrony.conf</code>:</p>
<pre><code class="language-ini"># Servidores NTS
server time.cloudflare.com iburst nts
server nts.netnod.se iburst nts
server ptbtime1.ptb.de iburst nts
server ptbtime2.ptb.de iburst nts
server ntppool1.time.nl iburst nts

# Persistir cookies NTS entre reinícios
ntsdumpdir /var/lib/chrony

# Drift file
driftfile /var/lib/chrony/chrony.drift

# Correção rápida na inicialização (max 1s de offset, 3 primeiros updates)
makestep 1.0 3

# Sincronizar RTC
rtcsync

# Log
logdir /var/log/chrony
</code></pre>
<p>Ative e inicie:</p>
<pre><code class="language-bash">sudo systemctl enable --now chronyd
</code></pre>
<p><strong>Desabilite o systemd-timesyncd</strong> (se estiver ativo), senão haverá conflito:</p>
<pre><code class="language-bash">sudo systemctl disable --now systemd-timesyncd
</code></pre>
<h3>Fedora</h3>
<p>Chrony já é o padrão. O NTS não é habilitado por padrão, mas a habilitação é trivial:</p>
<pre><code class="language-bash">sudo dnf install chrony  # provavelmente já instalado
</code></pre>
<p>Edite <code>/etc/chrony.conf</code>. Comente os pools padrão e adicione servidores NTS:</p>
<pre><code class="language-ini"># Comentar pools padrão (NTP sem autenticação)
# pool 2.fedora.pool.ntp.org iburst

# Servidores NTS
server time.cloudflare.com iburst nts
server nts.netnod.se iburst nts
server ptbtime1.ptb.de iburst nts
server ptbtime3.ptb.de iburst nts
server ntppool2.time.nl iburst nts

# Persistir cookies NTS
ntsdumpdir /var/lib/chrony

driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
logdir /var/log/chrony

# Desabilitar NTP servers recebidos via DHCP
# (o ISP não deve ditar seu servidor de tempo)
</code></pre>
<p>Se o DHCP do seu provedor injeta servidores NTP (sim, isso acontece), remova ou comente a linha:</p>
<pre><code class="language-ini"># sourcedir /run/chrony-dhcp
</code></pre>
<p>Restart:</p>
<pre><code class="language-bash">sudo systemctl restart chronyd
</code></pre>
<h3>Debian / Ubuntu (pré-25.10)</h3>
<p>Ubuntu anteriores ao 25.10 usam <code>systemd-timesyncd</code>, que não suporta NTS. A migração:</p>
<pre><code class="language-bash">sudo apt install chrony
sudo systemctl disable --now systemd-timesyncd
sudo systemctl enable --now chronyd
</code></pre>
<p>Edite <code>/etc/chrony/chrony.conf</code> com a mesma configuração de servidores NTS acima. Em Debian, o path da config pode ser <code>/etc/chrony/chrony.conf</code> ou <code>/etc/chrony.conf</code> dependendo da versão.</p>
<p>Ubuntu 25.10+ já vem com chrony + NTS habilitado por padrão em instalações novas. Em upgrades, a migração é manual.</p>
<h2>Validação</h2>
<p>Após configurar, verifique que NTS está funcionando:</p>
<h3>Verificar fontes de tempo</h3>
<pre><code class="language-bash">chronyc -N sources
</code></pre>
<p>Saída esperada (o <code>*</code> indica a fonte selecionada como referência):</p>
<pre><code class="language-plaintext">MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================
^+ time.cloudflare.com           3   6    17     4  -1643us[-6247us] +/-   70ms
^- nts.netnod.se                 1   6    17     3    +17ms[  +17ms] +/-  148ms
^* ptbtime1.ptb.de               1   6    17     3  -2576us[-7179us] +/-  112ms
^+ ptbtime2.ptb.de               1   6    17     4  +1837us[-2767us] +/-  118ms
^+ ntppool1.time.nl              1   6    17     4  +5908us[+1304us] +/-  101ms
</code></pre>
<p><code>Reach</code> deve ser 377 (octal, significa 8 consultas consecutivas bem-sucedidas). Se for 0, o servidor não está respondendo.</p>
<h3>Verificar autenticação NTS</h3>
<pre><code class="language-bash">sudo chronyc -N authdata
</code></pre>
<p>Saída esperada:</p>
<pre><code class="language-plaintext">Name/IP address             Mode KeyID Type KLen Last Atmp  NAK Cook CLen
===============================================================
time.cloudflare.com          NTS     1   30  128  141    0    0    8   64
nts.netnod.se                NTS     1   15  256  140    0    0    8  100
ptbtime1.ptb.de              NTS     1   15  256  140    0    0    8  100
ptbtime2.ptb.de              NTS     1   15  256  140    0    0    8  100
ntppool1.time.nl             NTS     1   30  128  141    0    0    8   64
</code></pre>
<p>O que verificar:</p>
<ul>
<li><p><strong>Mode</strong> deve ser <code>NTS</code> (não <code>NTP</code>)</p>
</li>
<li><p><strong>KeyID, Type, KLen</strong> devem ser valores diferentes de zero</p>
</li>
<li><p><strong>NAK</strong> deve ser 0 (zero falhas de autenticação)</p>
</li>
<li><p><strong>Cook</strong> indica cookies disponíveis (8 é o padrão completo)</p>
</li>
<li><p><strong>Type 15</strong> = AEAD-AES-SIV-CMAC-256, o algoritmo padrão</p>
</li>
</ul>
<p>Se algum servidor mostrar <code>Mode: NTP</code> em vez de <code>NTS</code>, o handshake NTS-KE falhou. Causas comuns: firewall bloqueando porta TCP 4460 (NTS-KE), DNS não resolvendo o hostname, ou certificado TLS expirado no servidor.</p>
<h3>Verificar status geral</h3>
<pre><code class="language-bash">chronyc tracking
</code></pre>
<p>Mostra stratum, offset atual, frequência de correção e status do leap second. Um sistema bem sincronizado terá offset na faixa de microsegundos.</p>
<pre><code class="language-bash">Reference ID    : CFC5577C (time.cloudflare.com)
Stratum         : 4
Ref time (UTC)  : Wed Apr 01 19:15:42 2026
System time     : 0.000761374 seconds slow of NTP time
Last offset     : -0.001684829 seconds
RMS offset      : 0.004399488 seconds
Frequency       : 29.567 ppm slow
Residual freq   : -0.000 ppm
Skew            : 176.681 ppm
Root delay      : 0.138503209 seconds
Root dispersion : 0.006709417 seconds
Update interval : 63.1 seconds
Leap status     : Normal
</code></pre>
<h2>Considerações de firewall</h2>
<p>O NTS precisa de duas portas abertas para saída:</p>
<ul>
<li><p><strong>UDP 123</strong> (NTP): queries de tempo padrão</p>
</li>
<li><p><strong>TCP 4460</strong> (NTS-KE): handshake TLS para troca de chaves</p>
</li>
</ul>
<p>Se você opera em rede corporativa ou com firewall egress restritivo, a porta 4460 pode estar bloqueada.</p>
<p>Alguns ISPs também bloqueiam ou fazem rate-limit em pacotes NTP maiores (que incluem as extensões NTS), confundindo-os com tentativas de amplificação.</p>
<p>Se o NTS-KE falhar, o chrony por padrão não sincroniza com aquela fonte (comportamento seguro: melhor não sincronizar do que sincronizar sem autenticação).</p>
<h2>Boards ARM sem RTC</h2>
<p>Se você roda chrony em Raspberry Pi ou outros ARM boards sem RTC (Real-Time Clock), há um problema: na inicialização, o relógio do sistema pode estar tão deslocado que o certificado TLS do servidor NTS é rejeitado (porque o sistema acha que estamos em 1970 ou alguma data absurda).</p>
<p>Solução: adicione à configuração:</p>
<pre><code class="language-ini">nocerttimecheck 1
</code></pre>
<p>Isso permite que a primeira verificação de certificado ignore a validade temporal. Depois que o relógio sincroniza, as verificações subsequentes funcionam normalmente. Existe impacto de segurança (um certificado expirado seria aceito no primeiro boot), mas é um trade-off aceitável para hardware sem RTC.</p>
<h2>ntpd-rs: a alternativa em Rust</h2>
<p>Para quem prefere software com foco em segurança de memória, o ntpd-rs é um cliente e servidor NTP escrito em Rust, financiado pela ISRG (a mesma organização por trás do Let's Encrypt) através do projeto Prossimo. Suporta NTS nativamente.</p>
<p>Configuração básica em <code>/etc/ntpd-rs/ntp.toml</code>:</p>
<pre><code class="language-toml">[observability]
log-level = "warn"

[[source]]
mode = "nts"
address = "time.cloudflare.com"

[[source]]
mode = "nts"
address = "nts.netnod.se"

[[source]]
mode = "nts"
address = "ptbtime1.ptb.de"

[synchronization]
single-step-panic-threshold = 1800
startup-step-panic-threshold = { forward = "inf", backward = "inf" }
</code></pre>
<p>O ntpd-rs está disponível em algumas distros mas é menos maduro que o chrony. Para produção, chrony continua sendo a referência. Mas vale acompanhar o ntpd-rs, especialmente se segurança de memória é prioridade na sua stack.</p>
<h2>Conclusão</h2>
<p>NTP sem autenticação é mais uma herança dos anos 80 que nunca deveria ter chegado a 2026 sem correção. Mas aqui estamos. A boa notícia é que a correção existe (NTS), é padronizada (RFC 8915), está implementada nos clientes principais (chrony) e disponível em servidores públicos confiáveis.</p>
<p>A configuração leva 5 minutos. Menos que o tempo que você gastou lendo este artigo.</p>
<p>Se você seguiu a série até aqui, sua pilha de proteção agora cobre DNS (DNSCrypt/DoH/DoT), handshake TLS (ECH) e sincronização de tempo (NTS). Três protocolos que o seu ISP usava como janela de observação, agora fechados.</p>
<p>O próximo passo natural é olhar para o que sai da sua máquina sem você saber. Auditoria de tráfego egress com opensnitch, ss e tcpdump. Mas isso fica para o próximo artigo.</p>
<p>Referências e leitura complementar:</p>
<ul>
<li><p>RFC 8915 - Network Time Security for the Network Time Protocol: <a href="https://datatracker.ietf.org/doc/html/rfc8915">https://datatracker.ietf.org/doc/html/rfc8915</a></p>
</li>
<li><p>Attacking the Network Time Protocol (BU, 2015): <a href="https://www.cs.bu.edu/~goldbe/papers/NTPattack.pdf">https://www.cs.bu.edu/~goldbe/papers/NTPattack.pdf</a></p>
</li>
<li><p>Lista de servidores NTS: <a href="https://github.com/jauderho/nts-servers">https://github.com/jauderho/nts-servers</a></p>
</li>
<li><p>chrony NTS (ArchWiki): <a href="https://wiki.archlinux.org/title/Chrony">https://wiki.archlinux.org/title/Chrony</a></p>
</li>
<li><p>Red Hat - NTS in chrony: <a href="https://docs.redhat.com/en/documentation/red%5C_hat%5C_enterprise%5C_linux/10/html/configuring%5C_time%5C_synchronization/overview-of-network-time-security-nts-in-chrony">https://docs.redhat.com/en/documentation/red\_hat\_enterprise\_linux/10/html/configuring\_time\_synchronization/overview-of-network-time-security-nts-in-chrony</a></p>
</li>
<li><p>Fedora NTS: <a href="https://fedoraproject.org/wiki/Changes/NetworkTimeSecurity">https://fedoraproject.org/wiki/Changes/NetworkTimeSecurity</a></p>
</li>
<li><p>Cloudflare Time Services: <a href="https://developers.cloudflare.com/time-services/nts/">https://developers.cloudflare.com/time-services/nts/</a></p>
</li>
<li><p>ntpd-rs (Prossimo/ISRG): <a href="https://github.com/pendulum-project/ntpd-rs">https://github.com/pendulum-project/ntpd-rs</a></p>
</li>
<li><p>NTP Tester (verificação NTS): <a href="https://www.ntp-tester.eu/nts.html">https://www.ntp-tester.eu/nts.html</a></p>
</li>
<li><p>Série DNSCrypt: <a href="https://esli.blog.br/dnscrypt-proxy">https://esli.blog.br/dnscrypt-proxy</a></p>
</li>
<li><p>Não confie no seu provedor: <a href="https://esli.blog.br/nao-confie-no-seu-provedor-de-internet">https://esli.blog.br/nao-confie-no-seu-provedor-de-internet</a></p>
</li>
<li><p>SNI Leak e ECH: <a href="https://esli.blog.br/sni-leak-ech">https://esli.blog.br/sni-leak-ech</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[SNI Leak: o calcanhar de Aquiles do DNS seguro]]></title><description><![CDATA[Você configurou DNSCrypt. Ativou DoH. Trocou o DNS do provedor por um que respeita privacidade. Fez tudo certo. E mesmo assim, o seu provedor de internet pode continuar sabendo exatamente quais sites ]]></description><link>https://esli.blog.br/sni-leak-o-calcanhar-de-aquiles-do-dns-seguro</link><guid isPermaLink="true">https://esli.blog.br/sni-leak-o-calcanhar-de-aquiles-do-dns-seguro</guid><category><![CDATA[SNI]]></category><category><![CDATA[dns]]></category><category><![CDATA[dnscrypt]]></category><category><![CDATA[DNS over https]]></category><category><![CDATA[DNS over TLS]]></category><category><![CDATA[DNS-over-QUIC]]></category><category><![CDATA[TLS]]></category><category><![CDATA[https]]></category><category><![CDATA[hacking]]></category><category><![CDATA[leaks]]></category><category><![CDATA[TCP Handshake]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Thu, 02 Apr 2026 12:51:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/9cefcb8e-d4d6-44ef-b12a-a3e859476b92.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Você configurou DNSCrypt. Ativou DoH. Trocou o DNS do provedor por um que respeita privacidade. Fez tudo certo. E mesmo assim, o seu provedor de internet pode continuar sabendo exatamente quais sites você acessa.</p>
<p>Bem-vindo ao problema do SNI.</p>
<p>Se você acompanhou a série sobre <a href="https://esli.blog.br/dnscrypt-dns-stamps-e-dns-criptografado-o-guia-que-faltava">DNSCrypt</a> e o artigo sobre <a href="https://esli.blog.br/nao-confie-no-seu-provedor-de-internet">por que não confiar no seu provedor de internet</a>, já sabe que criptografar as consultas DNS é o primeiro passo para recuperar privacidade na rede. Mas DNS é só metade da equação: outra metade acontece no TLS handshake, e é ali que mora o vazamento que quase ninguém discute.</p>
<h2>O que é o SNI e por que ele existe</h2>
<p>SNI significa Server Name Indication. É um campo enviado pelo cliente (seu navegador) no início de uma conexão TLS, antes de qualquer criptografia do conteúdo.</p>
<p>O motivo é prático: quando múltiplos sites compartilham o mesmo IP (o que é extremamente comum em hospedagens compartilhadas, CDNs e plataformas cloud), o servidor precisa saber qual certificado TLS apresentar. O cliente informa isso enviando o hostname de destino no ClientHello, a primeira mensagem do handshake TLS. Em texto claro.</p>
<p>Isso significa que qualquer entidade posicionada entre você e o servidor de destino (ISP, operador de rede corporativa, governo, Wi-Fi do aeroporto) consegue ler o campo SNI e saber exatamente qual domínio você está acessando.</p>
<p>Resumindo: HTTPS protege o conteúdo. O SNI entrega o destino.</p>
<h2>O que o atacante vê (e o que ele faz com isso)</h2>
<p>Com acesso ao SNI, um observador de rede consegue:</p>
<p><strong>Construir um perfil completo de navegação.</strong> Mesmo sem ver o conteúdo das páginas, saber que alguém acessou <code>consultamedica.com.br</code>, <code>vagas.com</code> e <code>advogadotrabalhista.com.br</code> no mesmo dia já conta uma história.</p>
<p><strong>Bloquear sites seletivamente.</strong> A Coreia do Sul fez exatamente isso em 2019: depois que os usuários começaram a contornar bloqueios DNS, o governo instruiu os ISPs a inspecionar o campo SNI nos handshakes TLS para derrubar conexões a domínios proibidos. O DNS criptografado virou inútil. O SNI era o novo ponto de controle.</p>
<p><strong>Censurar sem quebrar criptografia.</strong> O ISP não precisa decifrar o tráfego HTTPS. Basta ler o SNI, comparar com uma lista e dropar o pacote SYN ou enviar um RST. É trivial de implementar em DPI (Deep Packet Inspection) e invisível para quem não está monitorando.</p>
<p><strong>Correlacionar tráfego com identidade.</strong> Combinando SNI com IP de origem e timestamps, é possível vincular padrões de acesso a um assinante específico. Isso é feito sistematicamente em regimes autoritários e, como demonstramos no artigo anterior, por ISPs em democracias que retêm logs por obrigação legal.</p>
<p>O DNS cifrado resolve a pergunta "para qual IP este domínio aponta?". O SNI vaza a resposta: "qual domínio estou visitando?". São dois canais de metadados diferentes. Proteger um e ignorar o outro é como trancar a porta da frente e deixar a janela aberta.</p>
<h2>A evolução: do ESNI ao ECH</h2>
<p>A comunidade técnica não ignorou o problema. A primeira tentativa de solução foi o ESNI (Encrypted Server Name Indication), proposto em 2018 como extensão experimental do TLS 1.3. A ideia era simples: criptografar o campo SNI usando uma chave pública disponível via DNS.</p>
<p>O ESNI funcionou como prova de conceito, mas tinha limitações práticas. A criptografia era aplicada somente ao SNI, deixando outros campos do ClientHello (como ALPN, lista de cipher suites, e extensões) ainda visíveis. Isso permitia que observadores inferissem informações do destino mesmo sem o SNI explícito. O ESNI também dependia de registros DNS TXT específicos, o que tornava a distribuição de chaves frágil e difícil de escalar.</p>
<p>A resposta foi o ECH (Encrypted Client Hello), que substituiu o ESNI e está em processo de padronização final no IETF (draft 25 no momento desta publicação). A diferença fundamental: em vez de criptografar apenas o SNI, o ECH criptografa o ClientHello inteiro.</p>
<h2>Como o ECH funciona</h2>
<p>O mecanismo do ECH divide o ClientHello em duas partes:</p>
<p><strong>Outer ClientHello</strong> (público): Contém informações genéricas como versão do TLS, cipher suites e um SNI genérico. No caso do Cloudflare, todas as conexões ECH mostram <code>cloudflare-ech.com</code> como SNI externo. O observador de rede vê apenas que você está acessando "algo no Cloudflare", junto com milhões de outros usuários.</p>
<p><strong>Inner ClientHello</strong> (cifrado): Contém o SNI real, as extensões sensíveis e todas as informações que antes eram enviadas em texto claro. Esse bloco é criptografado usando uma chave pública (ECHConfig) que o navegador obtém via registro HTTPS/SVCB no DNS.</p>
<p>Para o ISP ou qualquer intermediário, a conexão TLS parece ser para <code>cloudflare-ech.com</code>. O destino real só é revelado dentro do túnel criptografado, acessível apenas pelo servidor de destino (ou pela CDN que o hospeda).</p>
<p>Pense assim: sem ECH, é como enviar uma carta com o nome do destinatário escrito no envelope. Com ECH, o envelope mostra "Cloudflare" e o nome real está dentro, lacrado.</p>
<h2>Dependência do DNS criptografado</h2>
<p>Aqui está o ponto que liga tudo: o ECH depende de registros DNS para funcionar. O navegador precisa buscar o registro HTTPS/SVCB do domínio para obter a ECHConfig (a chave pública de criptografia). Se essa consulta DNS for feita em texto claro, um atacante pode simplesmente remover ou modificar o registro para impedir o ECH.</p>
<p>Sem DoH, DoT ou DNSCrypt, o ECH pode ser sabotado antes de começar.</p>
<p>É por isso que a série sobre DNSCrypt não é "só sobre DNS". Ela é a fundação para que o ECH funcione. Um não substitui o outro. Eles se complementam.</p>
<p>A cadeia completa para privacidade real é:</p>
<ol>
<li><p><strong>DNS criptografado</strong> (DNSCrypt, DoH, DoT) impede que o ISP saiba quais domínios você resolve</p>
</li>
<li><p><strong>ECH</strong> impede que o ISP saiba quais domínios você acessa via TLS</p>
</li>
<li><p><strong>HTTPS</strong> impede que o ISP leia o conteúdo da comunicação</p>
</li>
</ol>
<p>Remova qualquer uma dessas camadas e a proteção degrada. As três juntas eliminam os metadados de navegação visíveis para observadores de rede.</p>
<h2>Suporte atual: quem já implementou</h2>
<h3>Navegadores</h3>
<table>
<thead>
<tr>
<th>Navegador</th>
<th>ECH habilitado por padrão</th>
<th>Desde quando</th>
</tr>
</thead>
<tbody><tr>
<td>Firefox</td>
<td>Sim</td>
<td>Versão 119 (out/2023)</td>
</tr>
<tr>
<td>Chrome</td>
<td>Sim</td>
<td>Versão 117+ (rollout gradual)</td>
</tr>
<tr>
<td>Edge</td>
<td>Sim</td>
<td>Segue Chromium</td>
</tr>
<tr>
<td>Brave</td>
<td>Sim</td>
<td>Segue Chromium</td>
</tr>
<tr>
<td>Safari</td>
<td>Sim</td>
<td>macOS Sequoia / iOS 18+</td>
</tr>
<tr>
<td>Tor Browser</td>
<td>Sim</td>
<td>Baseado no Firefox ESR</td>
</tr>
<tr>
<td>Mullvad Browser</td>
<td>Sim</td>
<td>Baseado no Firefox</td>
</tr>
</tbody></table>
<p>O Firefox foi o primeiro a ativar ECH por padrão, e exige que o DoH esteja habilitado para que o ECH funcione (o que faz sentido técnico). O Chrome e derivados fazem rollout progressivo.</p>
<h3>Servidores/CDNs</h3>
<p>O Cloudflare é o principal motor de adoção do ECH no lado servidor. Ativou ECH em todos os planos, incluindo o gratuito (onde não pode ser desabilitado). Isso é relevante porque uma parte significativa dos sites da internet usa Cloudflare como CDN/proxy reverso.</p>
<p>Dados de 2026: aproximadamente 4,2% dos top 100K sites e 9,2% do top 1M suportam ECH. Parece pouco, mas considerando que o Cloudflare sozinho cobre uma fatia enorme do tráfego web, o impacto prático é maior do que os números sugerem.</p>
<p>Outros CDNs e provedores de hospedagem ainda estão avaliando. Sem suporte do servidor, o ECH simplesmente não é negociado e a conexão cai no comportamento antigo (SNI em texto claro).</p>
<h2>Como verificar e configurar no Linux</h2>
<h3>Firefox</h3>
<p>O ECH já está habilitado por padrão no Firefox 119+.</p>
<p>Para confirmar:</p>
<ol>
<li><p>Acesse <code>about:config</code></p>
</li>
<li><p>Busque <code>network.dns.echconfig.enabled</code> → deve estar <code>true</code></p>
</li>
<li><p>Busque <code>network.dns.http3_echconfig.enabled</code> → deve estar <code>true</code></p>
</li>
</ol>
<p>O ECH no Firefox depende do DoH estar ativo. Verifique em: <code>Configurações → Privacidade e Segurança → DNS sobre HTTPS</code></p>
<p>Ative com Proteção Máxima e selecione um provedor (Cloudflare, NextDNS ou customizado).</p>
<h3>Chromium/Brave/Edge</h3>
<p>No Chrome e derivados, o ECH era controlado pela flag até a versão 117</p>
<pre><code class="language-plaintext">chrome://flags/#encrypted-client-hello
</code></pre>
<p>Atualmente, se o DoH está ativo e o servidor suporta ECH, o Chrome negocia automaticamente e não existe a opção de ser desativado.</p>
<p>Novamente, assim como no Firefox, o ECH depende de Secure DNS estar ativo. Verifique em: <code>Configurações → Privacidade e segurança → Segurança → Usar DNS seguro</code></p>
<h3>Checando sites com comando dig</h3>
<pre><code class="language-plaintext">dig HTTPS crypto.cloudflare.com +short
</code></pre>
<p>Se retornar campo com <code>ech=</code>, o site suporta ECH.</p>
<p>A presença de ECHConfig no registro DNS tipo HTTPS é condição necessária e suficiente para afirmar que o site suporta ECH. O browser negocia se quiser - mas o suporte é do servidor.</p>
<h3>Validação</h3>
<p>Para verificar se o ECH está funcionando na sua conexão:</p>
<ol>
<li><p>Acesse <a href="https://crypto.cloudflare.com/cdn-cgi/trace">https://crypto.cloudflare.com/cdn-cgi/trace</a> e procure o campo <code>sni=encrypted</code></p>
</li>
<li><p>Acesse <a href="https://defo.ie/ech-check.php">https://defo.ie/ech-check.php</a> para um teste mais detalhado</p>
</li>
</ol>
<h2>O que o ECH não resolve</h2>
<p>O ECH criptografa o ClientHello, isso é significativo mas não é o fim da história.</p>
<p><strong>IP de destino.</strong> O ECH esconde o domínio, não o IP. Se um servidor hospeda um único site, o IP já revela o destino. O ECH é mais eficaz quando muitos sites compartilham a mesma infraestrutura (como em CDNs).</p>
<p><strong>Análise de tráfego.</strong> O volume de dados, padrões de acesso e timing ainda são observáveis. Técnicas de traffic fingerprinting podem inferir o site visitado mesmo sem SNI.</p>
<p><strong>DNS não criptografado.</strong> Se o DNS vazar o domínio antes do ECH atuar, a proteção é nula. O ECH precisa de DoH/DoT/DNSCrypt para funcionar como planejado.</p>
<p><strong>Servidores sem suporte.</strong> Se o site que você acessa não suporta ECH, o SNI continua em texto claro. A proteção depende da adoção do lado servidor.</p>
<p>Para uma cobertura mais completa, combine ECH com VPN. Conforme discutido no artigo sobre <a href="https://esli.blog.br/qual-melhor-vpn">qual a melhor VPN</a>, uma VPN oculta o IP de destino e encapsula todo o tráfego, enquanto o ECH protege os metadados TLS. VPN + ECH + DNS criptografado é a combinação mais robusta disponível hoje sem utilizar o Tor.</p>
<h2>ECH como ferramenta de ataque</h2>
<p>Vale registrar o outro lado: o ECH também é útil para atacantes. Em 2024, pesquisadores da NTT Security Holdings identificaram um malware (batizado de ECHidna) que usava ECH para esconder comunicação com servidores de comando e controle (C2). O tráfego malicioso se passava por conexões legítimas a infraestrutura CDN, tornando a detecção por firewalls tradicionais ineficaz.</p>
<p>Isso não é argumento contra o ECH, ao contrário: mostra que a tecnologia e a criptografia funcionam, o que muda é a intenção de uso.</p>
<h2>Escondendo SNI do seu provedor e de atacantes</h2>
<p><a href="https://github.com/bol-van/zapret"><strong>zapret</strong></a> e <a href="https://github.com/xvzc/SpoofDPI"><strong>SpoofDPI</strong></a> são ferramentas que operam na camada de rede para impedir que sistemas de Deep Packet Inspection (DPI) consigam ler o campo SNI no ClientHello do TLS.</p>
<p>No Linux, o <strong>zapret</strong> usa nfqueue (via iptables/nftables) para interceptar pacotes de saída antes de deixarem a máquina — ao capturar o ClientHello, ele aplica técnicas como fragmentação TCP (split2), manipulação de TTL e inserção de pacotes falsos (fake), fazendo com que o DPI do ISP receba os fragmentos fora de ordem ou com dados inválidos enquanto o servidor de destino remonta corretamente.</p>
<p>Já o <strong>SpoofDPI</strong> atua como proxy HTTP/HTTPS local: o navegador conecta nele, e ele estabelece a conexão real com o destino fragmentando o primeiro pacote TLS no nível da aplicação — mais simples de configurar (basta apontar o proxy do browser para 127.0.0.1:8080), porém menos flexível que o zapret. Ambos <strong>não criptografam nem removem o SNI</strong> — apenas tornam a inspeção passiva inviável ao quebrar as heurísticas dos equipamentos de DPI.</p>
<p>No Android, as principais opções são o <a href="https://github.com/Gedsh/InviZible"><strong>InviZible Pro</strong></a>, <a href="https://github.com/dovecoteescapee/ByeDPIAndroid"><strong>ByeDPI Android</strong></a> e <a href="https://github.com/nomoresat/DPITunnel-android"><strong>DPI Tunnel</strong></a> — todos funcionam sem root criando uma VPN local no dispositivo que intercepta o tráfego de saída e aplica técnicas de fragmentação/dessincronização no ClientHello TLS antes que ele chegue ao ISP, impedindo que o DPI passivo consiga ler o SNI.</p>
<p>O <strong>InviZible Pro</strong> é o mais completo, integrando DNSCrypt, Tor e módulos anti-DPI em um único app (com root, ele injeta regras iptables diretas, dispensando a VPN local e evitando conflitos). Possui opção para falsificar o SNI.</p>
<p>O <strong>ByeDPI Android</strong> é o mais simples e focado: instala, escolhe o método de desync (split/disorder) e ativa — sem configuração extra. Assim como no Linux, <strong>nenhum deles criptografa ou remove o SNI</strong>, apenas fragmentam o pacote TCP para que equipamentos de inspeção passiva não consigam remontar e ler o campo em tempo real.</p>
<h2>Conclusão: o elo que faltava</h2>
<p>Na prática, do lado do usuário final, o ECH é quase inteiramente dependente do navegador e do servidor (qualquer fork do Chrome/Chromium atualizado, e qualquer Firefox desde que validado o <code>true</code> nas configs).<br />O que o usuário controla é diretamente limitado, mas já está no artigo:</p>
<ul>
<li><p>Habilitar DoH/DoT/DNSCrypt (pré-requisito para ECH funcionar);</p>
</li>
<li><p>Validar que ECH está ativo no browser (about:config, flags, testes online);</p>
</li>
<li><p>Desabilitar WebRTC. Não é SNI diretamente, mas WebRTC vaza IP real mesmo com VPN/ECH, o que permite correlação e é um complemento lógico;</p>
</li>
</ul>
<p>O ECH é a peça que conecta a série de proteções que temos construído aqui no blog. DNSCrypt protege a resolução de nomes, HTTPS protege o conteúdo e o ECH protege o handshake.</p>
<p>Sem ECH, o SNI é o último canal de metadados aberto para observadores de rede. Com ECH, esse canal fecha. O ISP deixa de saber qual site você visita, não apenas o que você faz dentro dele.</p>
<p>A adoção ainda está em progresso. Mas o suporte nos navegadores já é universal, o Cloudflare empurra a adoção no lado servidor, e distribuições Linux como Ubuntu e Fedora facilitam a configuração de DoH/DoT como requisito base.</p>
<p>Se você já configurou DNSCrypt seguindo a série anterior, validar que o ECH está habilitado no navegador é questão de segundos.</p>
<p>Referências e leitura complementar:</p>
<ul>
<li><p>RFC 8744 - Issues and Requirements for SNI Encryption in TLS</p>
</li>
<li><p>IETF Draft ECH: <a href="https://datatracker.ietf.org/doc/draft-ietf-tls-esni/">https://datatracker.ietf.org/doc/draft-ietf-tls-esni/</a></p>
</li>
<li><p>Cloudflare ECH: <a href="https://blog.cloudflare.com/announcing-encrypted-client-hello/">https://blog.cloudflare.com/announcing-encrypted-client-hello/</a></p>
</li>
<li><p>CDT - Encrypted Client Hello: Closing the SNI Metadata Gap</p>
</li>
<li><p>Cisco ECH Defense Strategies (análise do lado corporativo/firewall)</p>
</li>
<li><p><a href="https://defo.ie/ech-check.php">https://defo.ie/ech-check.php</a> (verificador ECH)</p>
</li>
<li><p><a href="https://crypto.cloudflare.com/cdn-cgi/trace">https://crypto.cloudflare.com/cdn-cgi/trace</a> (verificador Cloudflare)</p>
</li>
<li><p>Série DNSCrypt: <a href="https://esli.blog.br/dnscrypt-proxy">https://esli.blog.br/dnscrypt-proxy</a></p>
</li>
<li><p>Não confie no seu provedor: <a href="https://esli.blog.br/nao-confie-no-seu-provedor-de-internet">https://esli.blog.br/nao-confie-no-seu-provedor-de-internet</a></p>
</li>
<li><p>Qual melhor VPN: <a href="https://esli.blog.br/qual-melhor-vpn">https://esli.blog.br/qual-melhor-vpn</a></p>
</li>
<li><p>Qual melhor navegador: <a href="https://esli.blog.br/qual-melhor-navegador">https://esli.blog.br/qual-melhor-navegador</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[DNS criptografado no Android: InviZible Pro e alternativas]]></title><description><![CDATA[Terceiro e último artigo da série sobre DNS criptografado. No primeiro, expliquei o protocolo DNSCrypt, os DNS Stamps, relays e o ecossistema de DNS criptografado. No segundo, configurei o dnscrypt-pr]]></description><link>https://esli.blog.br/dns-criptografado-no-android-invizible-pro-e-alternativas</link><guid isPermaLink="true">https://esli.blog.br/dns-criptografado-no-android-invizible-pro-e-alternativas</guid><category><![CDATA[dns]]></category><category><![CDATA[DNS over https]]></category><category><![CDATA[DNS-over-QUIC]]></category><category><![CDATA[DNS over TLS]]></category><category><![CDATA[invizible]]></category><category><![CDATA[Android]]></category><category><![CDATA[https]]></category><category><![CDATA[TLS]]></category><category><![CDATA[Security]]></category><category><![CDATA[privacy]]></category><category><![CDATA[dnscrypt]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Wed, 01 Apr 2026 16:59:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/13978cc0-82c3-4187-99b8-86054a5bbcd4.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Terceiro e último artigo da série sobre DNS criptografado. No <a href="https://esli.blog.br/dnscrypt-dns-stamps-e-dns-criptografado-o-guia-que-faltava">primeiro</a>, expliquei o protocolo DNSCrypt, os DNS Stamps, relays e o ecossistema de DNS criptografado. No <a href="https://esli.blog.br/dnscrypt-proxy-no-linux-configurando-dns-criptografado">segundo</a>, configurei o dnscrypt-proxy no Linux com NextDNS.</p>
<p>Agora é a vez do Android. O objetivo é o mesmo: queries DNS criptografadas via DoH usando o NextDNS como resolver, mas com o dnscrypt-proxy rodando via InviZible Pro, alternativas e o que o Android oferece nativamente.</p>
<h2>O que o Android já oferece (e por que não é suficiente)</h2>
<p>Desde o Android 9, existe a opção "DNS Privado" em Configurações &gt; Rede. Funciona com DoT (DNS-over-TLS) apontando para um hostname do tipo <code>abc123.dns.nextdns.io</code> (onde <code>abc123</code> é seu config ID do NextDNS).</p>
<p>Funciona? Sim. Mas tem limitações:</p>
<ul>
<li><p>Só suporta DoT. Sem DoH, sem DNSCrypt, sem ODoH.</p>
</li>
<li><p>Sem cache local configurável.</p>
</li>
<li><p>Sem controle sobre qual app usa qual DNS.</p>
</li>
<li><p>Sem firewall integrado.</p>
</li>
<li><p>Sem fallback configurável.</p>
</li>
<li><p>Se o servidor DoT não responder, o Android pode fazer fallback para o DNS do provedor sem avisar (dependendo da opção: "automático" faz fallback, "estrito" bloqueia).</p>
</li>
<li><p>Não há logs para debug.</p>
</li>
</ul>
<p>Para a maioria das pessoas, DNS Privado com NextDNS no modo estrito já é um avanço enorme sobre o DNS do provedor. Mas se você quer controle real, precisa de algo mais.</p>
<h2>InviZible Pro: a solução completa</h2>
<p>O InviZible Pro é um aplicativo Android open-source que integra três módulos de privacidade em um único pacote:</p>
<table>
<thead>
<tr>
<th>Módulo</th>
<th>Software subjacente</th>
<th>Função</th>
</tr>
</thead>
<tbody><tr>
<td>DNSCrypt</td>
<td>dnscrypt-proxy</td>
<td>DNS criptografado</td>
</tr>
<tr>
<td>Tor</td>
<td>tor</td>
<td>Anonimização de tráfego</td>
</tr>
<tr>
<td>I2P</td>
<td>Purple I2P (i2pd)</td>
<td>Acesso à rede I2P</td>
</tr>
</tbody></table>
<p>Disponível no F-Droid (versão sem restrições) e na Google Play. O código-fonte está em <a href="https://github.com/Gedsh/InviZible">https://github.com/Gedsh/InviZible</a> sob licença GPLv3.</p>
<h3>O que ele faz</h3>
<p><strong>Funciona com e sem root.</strong> Com root, redireciona tráfego via iptables (mais eficiente, sem overhead de VPN). Sem root, cria uma VPN local (o tráfego não sai do dispositivo, apenas é redirecionado internamente para os módulos).</p>
<p><strong>Firewall integrado.</strong> Controle granular por aplicativo: quem pode usar internet, quem passa pelo Tor, quem usa DNS direto. Isso substitui apps de firewall separados como o NetGuard.</p>
<p><strong>Kill switch.</strong> Se o módulo cair, o tráfego é bloqueado. Sem vazamentos acidentais de queries em texto puro para o DNS do provedor.</p>
<p><strong>Bridges Tor.</strong> Suporte a bridges obfs4, snowflake e webtunnel para contornar censura em redes restritivas.</p>
<p><strong>Configuração granular.</strong> Acesso direto aos arquivos <code>dnscrypt-proxy.toml</code>, <code>torrc</code> e <code>i2pd.conf</code> dentro do app com editor de texto integrado.</p>
<p><strong>Logs em tempo real.</strong> Cada módulo tem sua aba de log. Debug sem precisar de Termux ou logcat.</p>
<p><strong>Atualizações independentes.</strong> Os binários do dnscrypt-proxy, Tor e Purple I2P são atualizados separadamente do app. Na versão mais recente (7.4.0, março de 2026): dnscrypt-proxy 2.1.15, Tor 4.8.22, Purple I2P 2.59.0.</p>
<p><strong>Stealth Mode.</strong> Evasão de DPI (Deep Packet Inspection) para cenários de censura.</p>
<p>Em resumo: substitui VPN + firewall + adblock DNS em um único app, sem ads, sem rastreio, sem assinatura para as funcionalidades core. A versão paga destrava apenas o tema Material Design escuro.</p>
<h2>Configurando NextDNS no InviZible Pro</h2>
<h3>Pré-requisitos</h3>
<ul>
<li><p>InviZible Pro instalado (F-Droid: <code>pan.alexander.tordnscrypt.stable</code> ou Play Store)</p>
</li>
<li><p>Conta no NextDNS com um perfil configurado</p>
</li>
<li><p>Seu config ID (visível em <a href="https://my.nextdns.io">https://my.nextdns.io</a> na aba Setup)</p>
</li>
</ul>
<h3>Passo 1: Obter o stamp</h3>
<p><strong>Forma rápida:</strong> acesse <a href="https://my.nextdns.io">https://my.nextdns.io</a>, vá em Setup Guide &gt; Routers ou Linux, seção DNSCrypt. O stamp já está pronto com seu config ID.</p>
<p><strong>Forma manual:</strong> acesse <a href="https://dnscrypt.info/stamps/">https://dnscrypt.info/stamps/</a> e preencha:</p>
<table>
<thead>
<tr>
<th>Campo</th>
<th>Valor</th>
</tr>
</thead>
<tbody><tr>
<td>Protocol</td>
<td>DNS-over-HTTPS</td>
</tr>
<tr>
<td>IP Address</td>
<td>(vazio)</td>
</tr>
<tr>
<td>Host name</td>
<td>dns.nextdns.io</td>
</tr>
<tr>
<td>Hashes</td>
<td>(vazio)</td>
</tr>
<tr>
<td>Path</td>
<td>/SEU_ID (ex: /abc123)</td>
</tr>
<tr>
<td>No logs</td>
<td>marcado</td>
</tr>
<tr>
<td>No filter</td>
<td>desmarcado</td>
</tr>
<tr>
<td>DNSSEC</td>
<td>marcado</td>
</tr>
</tbody></table>
<p>O path DEVE começar com <code>/</code>. Se quiser identificar o dispositivo no painel do NextDNS, use <code>/abc123/android-pixel</code> ou similar.</p>
<p>Copie o stamp gerado. Algo como:</p>
<pre><code class="language-plaintext">sdns://AgMAAAAAAAAAAAAADmRucy5uZXh0ZG5zLmlvBy9hYmMxMjM
</code></pre>
<h3>Passo 2: Configurar via interface do InviZible Pro</h3>
<ol>
<li><p>Abra o InviZible Pro</p>
</li>
<li><p>No card DNSCrypt, toque no ícone de engrenagem</p>
</li>
<li><p>Acesse <strong>DNSCrypt servers</strong> e desmarque todos os servidores pré-configurados</p>
</li>
<li><p>Acesse <strong>Own servers / DNS Stamp</strong> (o nome pode variar conforme a versão)</p>
</li>
<li><p>Cole o stamp do passo anterior</p>
</li>
<li><p>Dê um nome ao servidor (ex: <code>nextdns</code>)</p>
</li>
<li><p>Salve</p>
</li>
</ol>
<h3>Passo 2 (alternativo): Editar o dnscrypt-proxy.toml</h3>
<p>Se você prefere controle total (e já sabe o que está fazendo):</p>
<ol>
<li><p>Menu &gt; Common Settings &gt; Open text editor</p>
</li>
<li><p>Selecione <code>dnscrypt-proxy.toml</code></p>
</li>
<li><p>Edite:</p>
</li>
</ol>
<pre><code class="language-toml"># Forçar uso exclusivo do NextDNS
server_names = ['nextdns']

# Cache local (recomendado, especialmente no plano free)
cache = true
cache_size = 4096
cache_min_ttl = 2400
cache_max_ttl = 86400

# Servidor estático com seu stamp
[static]
  [static.'nextdns']
  stamp = 'sdns://AgMAAAAAAAAAAAAADmRucy5uZXh0ZG5zLmlvBy9hYmMxMjM'
</code></pre>
<ol>
<li>Salve e feche o editor</li>
</ol>
<h3>Passo 3: Reiniciar e validar</h3>
<ol>
<li><p>No card DNSCrypt, pare o módulo (Stop) e inicie novamente (Start)</p>
</li>
<li><p>Verifique os logs do DNSCrypt. Deve aparecer o servidor <code>nextdns</code> como ativo com status OK</p>
</li>
<li><p>No navegador, acesse <a href="https://test.nextdns.io">https://test.nextdns.io</a></p>
</li>
</ol>
<p>Se tudo estiver correto, a página retorna seu config ID e status "connected" ou "using NextDNS".</p>
<p>Se retornar "not using NextDNS":</p>
<ul>
<li><p>Revise o stamp (o path tem a <code>/</code> inicial? O config ID está correto?)</p>
</li>
<li><p>Verifique se não há outro servidor marcado nas configurações do DNSCrypt</p>
</li>
<li><p>Nos logs, procure mensagens de erro relacionadas ao stamp</p>
</li>
</ul>
<h3>Passo 4: Ajustes adicionais</h3>
<p><strong>DNS e Tor juntos (cuidado):</strong></p>
<p>Se o módulo Tor estiver ativo, por padrão as queries DNS são roteadas pelo Tor antes de chegar ao NextDNS. Isso:</p>
<ul>
<li><p>Esconde seu IP real do NextDNS (pode ser desejável)</p>
</li>
<li><p>Aumenta a latência consideravelmente (indesejável para uso diário)</p>
</li>
<li><p>Pode fazer o NextDNS não aplicar regras baseadas em localização</p>
</li>
</ul>
<p>Para desabilitar: Common Settings &gt; desmarque "Route DNS through Tor".</p>
<p><strong>Consumo de bateria:</strong></p>
<p>O DNSCrypt sozinho consome pouco. O Tor consome mais. Se usar apenas o módulo DNSCrypt (sem Tor e sem I2P), o impacto na bateria é mínimo. Segundo a documentação do InviZible, Tor + DNSCrypt 24/7 consome em torno de 8%.</p>
<p>Exclua o InviZible Pro da otimização de bateria do Android para evitar que o sistema mate o processo em background. Vá em Configurações &gt; Bateria &gt; Otimização de bateria &gt; InviZible Pro &gt; Não otimizar. Consulte <a href="https://dontkillmyapp.com">https://dontkillmyapp.com</a> para instruções específicas do seu fabricante (Samsung, Xiaomi/MIUI e Huawei são os piores nesse aspecto).</p>
<p><strong>Rate limit no plano free do NextDNS:</strong></p>
<p>O plano gratuito permite 300k queries/mês com filtragem ativa. Após o limite, o DNS continua resolvendo mas sem bloqueio e sem logs. O cache agressivo no <code>dnscrypt-proxy.toml</code> (<code>cache_min_ttl = 2400</code>) ajuda a reduzir o número de queries.</p>
<p>Monitore em <a href="https://my.nextdns.io">https://my.nextdns.io</a> &gt; Analytics.</p>
<h2>Alternativas ao InviZible Pro para DNSCrypt no Android</h2>
<p>O InviZible Pro não é a única opção e dependendo do que você precisa (ou até onde está disposto a ir), outras ferramentas podem atender.</p>
<h3>personalDNSfilter</h3>
<p>Open-source, disponível no F-Droid. Funciona como proxy DNS local com suporte a blocklists. Não usa dnscrypt-proxy internamente, mas suporta DoH e DoT como upstream. Mais leve que o InviZible, sem os módulos Tor/I2P. Se você quer apenas DNS filtrado sem o pacote completo de privacidade, é uma opção.</p>
<p><a href="https://www.zenz-solutions.de/personaldnsfilter-wp/">https://www.zenz-solutions.de/personaldnsfilter-wp/</a></p>
<h3>AdGuard (versão completa)</h3>
<p>A versão completa do AdGuard (não confundir com o AdGuard DNS) funciona como VPN local no Android e intercepta DNS. Suporta DoH, DoT e DNSCrypt como upstream. Tem bloqueio de ads ao nível de rede (não só DNS), filtro HTTPS para bloquear ads em conexões criptografadas e proteção contra tracking. A versão completa é paga e não está na Play Store (baixar via site oficial).</p>
<p><a href="https://adguard.com/en/adguard-android/overview.html">https://adguard.com/en/adguard-android/overview.html</a></p>
<h3>Rethink DNS + Firewall</h3>
<p>Open-source, no F-Droid. Combina firewall por app, DNS criptografado (DoH, DoT), blocklists e logs detalhados. Interface moderna. Não usa dnscrypt-proxy, mas suporta configuração de servidores DNS customizados via DoH. Não suporta o protocolo DNSCrypt nem stamps diretamente, mas aceita endpoints DoH como <code>https://dns.nextdns.io/abc123</code>.</p>
<p><a href="https://rethinkdns.com/">https://rethinkdns.com/</a></p>
<h3>DNS Privado nativo do Android</h3>
<p>Como mencionado, funciona apenas com DoT. Hostname do NextDNS: <code>abc123.dns.nextdns.io</code>. Sem firewall, sem cache configurável, sem logs. Mas é zero configuração e funciona em qualquer Android 9+.</p>
<h3>Comparativo rápido</h3>
<table>
<thead>
<tr>
<th>Feature</th>
<th>InviZible Pro</th>
<th>personalDNSfilter</th>
<th>AdGuard</th>
<th>Rethink DNS</th>
<th>DNS Privado</th>
</tr>
</thead>
<tbody><tr>
<td>Protocolo DNSCrypt</td>
<td>Sim</td>
<td>Não</td>
<td>Sim</td>
<td>Não</td>
<td>Não</td>
</tr>
<tr>
<td>DoH</td>
<td>Sim (via stamp)</td>
<td>Sim</td>
<td>Sim</td>
<td>Sim</td>
<td>Não</td>
</tr>
<tr>
<td>DoT</td>
<td>Não diretamente</td>
<td>Sim</td>
<td>Sim</td>
<td>Sim</td>
<td>Sim</td>
</tr>
<tr>
<td>DNS Stamps</td>
<td>Sim</td>
<td>Não</td>
<td>Sim</td>
<td>Não</td>
<td>Não</td>
</tr>
<tr>
<td>Tor integrado</td>
<td>Sim</td>
<td>Não</td>
<td>Não</td>
<td>Não</td>
<td>Não</td>
</tr>
<tr>
<td>I2P integrado</td>
<td>Sim</td>
<td>Não</td>
<td>Não</td>
<td>Não</td>
<td>Não</td>
</tr>
<tr>
<td>Firewall por app</td>
<td>Sim</td>
<td>Não</td>
<td>Sim</td>
<td>Sim</td>
<td>Não</td>
</tr>
<tr>
<td>Open-source</td>
<td>Sim (GPLv3)</td>
<td>Sim</td>
<td>Parcial</td>
<td>Sim</td>
<td>N/A</td>
</tr>
<tr>
<td>Root necessário</td>
<td>Não (VPN local)</td>
<td>Não</td>
<td>Não</td>
<td>Não</td>
<td>Não</td>
</tr>
<tr>
<td>F-Droid</td>
<td>Sim</td>
<td>Sim</td>
<td>Não</td>
<td>Sim</td>
<td>N/A</td>
</tr>
<tr>
<td>Custo</td>
<td>Grátis</td>
<td>Grátis</td>
<td>Pago</td>
<td>Grátis</td>
<td>Grátis</td>
</tr>
</tbody></table>
<h2>Resultado</h2>
<p>Com o InviZible Pro configurado, seu Android passa a ter o mesmo nível de proteção DNS que o desktop com dnscrypt-proxy. Mesmo stamp, mesmo config ID do NextDNS, mesmas blocklists, analytics unificado no painel.</p>
<p>O setup completo da série: primeiro artigo para entender o ecossistema, segundo para configurar no Linux (Fedora e Arch), terceiro para Android. Três ambientes, um resolver, queries criptografadas em todos.</p>
<p>Se o seu provedor de internet pudesse cobrar por cada consulta DNS que bisbilhota, já teria financiado um programa espacial. Criptografe suas queries.</p>
<p>Outros artigos relacionados:</p>
<ul>
<li><p><a href="https://esli.blog.br/dnscrypt-dns-stamps-guia">DNSCrypt, DNS Stamps e DNS Criptografado: o guia que faltava</a></p>
</li>
<li><p><a href="https://esli.blog.br/dnscrypt-proxy-linux-nextdns">dnscrypt-proxy no Linux: configurando DNS criptografado com NextDNS</a></p>
</li>
<li><p><a href="https://esli.blog.br/privacidade-e-seguranca-2025">Privacidade e Segurança (2025)</a></p>
</li>
<li><p><a href="https://esli.blog.br/vpn-nao-e-o-suficiente">VPN não é o suficiente</a></p>
</li>
<li><p><a href="https://esli.blog.br/como-fugir-das-propaganda-na-internet">Como fugir das propagandas na Internet</a></p>
</li>
<li><p><a href="https://esli.blog.br/qual-melhor-navegador">Qual melhor navegador</a></p>
</li>
</ul>
<p>Referências:</p>
<ul>
<li><p><a href="https://github.com/Gedsh/InviZible">https://github.com/Gedsh/InviZible</a></p>
</li>
<li><p><a href="https://invizible.net/en/">https://invizible.net/en/</a></p>
</li>
<li><p><a href="https://f-droid.org/packages/pan.alexander.tordnscrypt.stable/">https://f-droid.org/packages/pan.alexander.tordnscrypt.stable/</a></p>
</li>
<li><p><a href="https://github.com/DNSCrypt/dnscrypt-proxy">https://github.com/DNSCrypt/dnscrypt-proxy</a></p>
</li>
<li><p><a href="https://dnscrypt.info/stamps/">https://dnscrypt.info/stamps/</a></p>
</li>
<li><p><a href="https://my.nextdns.io">https://my.nextdns.io</a></p>
</li>
<li><p><a href="https://test.nextdns.io">https://test.nextdns.io</a></p>
</li>
<li><p><a href="https://dontkillmyapp.com">https://dontkillmyapp.com</a></p>
</li>
<li><p><a href="https://rethinkdns.com/">https://rethinkdns.com/</a></p>
</li>
<li><p><a href="https://adguard.com/en/adguard-android/overview.html">https://adguard.com/en/adguard-android/overview.html</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[dnscrypt-proxy no Linux: configurando DNS criptografado]]></title><description><![CDATA[Este é o segundo artigo da série sobre DNS criptografado. No primeiro, expliquei o que é o DNSCrypt, os protocolos de DNS criptografado, o conceito de DNS Stamps e relays. Se você caiu aqui direto, re]]></description><link>https://esli.blog.br/dnscrypt-proxy-no-linux-configurando-dns-criptografado</link><guid isPermaLink="true">https://esli.blog.br/dnscrypt-proxy-no-linux-configurando-dns-criptografado</guid><category><![CDATA[dns]]></category><category><![CDATA[Cryptography]]></category><category><![CDATA[https]]></category><category><![CDATA[TLS]]></category><category><![CDATA[criptografia]]></category><category><![CDATA[privacy]]></category><category><![CDATA[Security]]></category><category><![CDATA[DNS over https]]></category><category><![CDATA[DNS over TLS]]></category><category><![CDATA[DNS-over-QUIC]]></category><category><![CDATA[dnscrypt]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Wed, 01 Apr 2026 12:44:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/c4560645-055c-47ab-9803-e850d0d73984.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Este é o segundo artigo da série sobre DNS criptografado. No <a href="https://esli.blog.br/dnscrypt-dns-stamps-e-dns-criptografado-o-guia-que-faltava">primeiro</a>, expliquei o que é o DNSCrypt, os protocolos de DNS criptografado, o conceito de DNS Stamps e relays. Se você caiu aqui direto, recomendo ler o anterior antes de prosseguir.</p>
<p>O objetivo agora é prático: instalar o dnscrypt-proxy no Linux e configurar o NextDNS como resolver exclusivo via DoH, utilizando o stamp gerado conforme descrito no artigo anterior.</p>
<p>Uso NextDNS em todos os meus dispositivos, conforme descrevi no <a href="https://esli.blog.br/privacidade-e-seguranca-2025">Privacidade e Segurança (2025)</a>. Aqui vou mostrar como configurar usando o dnscrypt-proxy ao invés do cliente oficial do NextDNS ou do DNS Privado nativo.</p>
<h2>Por que dnscrypt-proxy ao invés do cliente NextDNS?</h2>
<p>O NextDNS oferece um CLI próprio (<code>nextdns</code> via <code>sh -c "$(curl -sL https://nextdns.io/install)"</code>). Funciona bem, é simples. Mas o dnscrypt-proxy oferece vantagens:</p>
<ul>
<li><p>Suporta múltiplos protocolos (DNSCrypt, DoH, ODoH)</p>
</li>
<li><p>Permite trocar de provider sem mudar a stack</p>
</li>
<li><p>Suporte a Anonymized DNSCrypt e relays</p>
</li>
<li><p>Cache local com TTL configurável</p>
</li>
<li><p>Cloaking, blocklists locais, forwarding rules</p>
</li>
<li><p>Logs detalhados para debug</p>
</li>
<li><p>Funciona idêntico em qualquer distro</p>
</li>
</ul>
<p>Se você quer apenas o NextDNS funcionando rápido, o CLI oficial resolve. Se quer controle granular ou planeja usar recursos além do que o NextDNS oferece nativamente, o dnscrypt-proxy é o caminho.</p>
<h2>Instalação</h2>
<h3>Fedora</h3>
<pre><code class="language-bash">sudo dnf install dnscrypt-proxy
</code></pre>
<p>O pacote instala o binário, o serviço systemd e o arquivo de configuração em <code>/etc/dnscrypt-proxy/dnscrypt-proxy.toml</code>.</p>
<h3>Arch / EndeavourOS / Omarchy</h3>
<pre><code class="language-bash">sudo pacman -S dnscrypt-proxy
</code></pre>
<p>Mesma estrutura. Arch mantém o pacote atualizado com frequência.</p>
<h3>Debian / Ubuntu</h3>
<pre><code class="language-bash">sudo apt install dnscrypt-proxy
</code></pre>
<p>Atenção: as versões nos repositórios do Debian/Ubuntu podem estar desatualizadas. Verifique a versão com <code>dnscrypt-proxy --version</code> e compare com os releases em <a href="https://github.com/DNSCrypt/dnscrypt-proxy/releases">https://github.com/DNSCrypt/dnscrypt-proxy/releases</a>. Se estiver muito defasado, instale manualmente via binário do GitHub.</p>
<h2>Obter o stamp do NextDNS</h2>
<p>Duas formas:</p>
<p><strong>Forma 1 (recomendada):</strong> acesse <a href="https://my.nextdns.io">https://my.nextdns.io</a>, vá em Setup Guide, selecione Linux ou Routers, e copie o stamp da seção DNSCrypt. Ele já vem com seu config ID embutido.</p>
<p><strong>Forma 2 (manual):</strong> acesse <a href="https://dnscrypt.info/stamps/">https://dnscrypt.info/stamps/</a> e preencha:</p>
<table>
<thead>
<tr>
<th>Campo</th>
<th>Valor</th>
</tr>
</thead>
<tbody><tr>
<td>Protocol</td>
<td>DNS-over-HTTPS</td>
</tr>
<tr>
<td>IP Address</td>
<td>(vazio)</td>
</tr>
<tr>
<td>Host name</td>
<td>dns.nextdns.io</td>
</tr>
<tr>
<td>Path</td>
<td>/SEU_ID (ex: /abc123)</td>
</tr>
<tr>
<td>No logs</td>
<td>marcado</td>
</tr>
<tr>
<td>DNSSEC</td>
<td>marcado</td>
</tr>
</tbody></table>
<p>Copie o stamp resultante (<code>sdns://...</code>).</p>
<p>Para identificar a máquina no painel do NextDNS, adicione o nome do dispositivo ao path: <code>/abc123/fedora-desktop</code>.</p>
<h2>Configuração</h2>
<p>Edite o arquivo principal:</p>
<pre><code class="language-bash">sudo vim /etc/dnscrypt-proxy/dnscrypt-proxy.toml
</code></pre>
<p>As configurações essenciais:</p>
<pre><code class="language-toml"># Porta de escuta
listen_addresses = ['127.0.0.1:53', '[::1]:53']

# Forçar uso exclusivo do NextDNS
server_names = ['nextdns']

# Habilitar IPv6 se sua rede suportar
ipv6_servers = false

# Requerer DNSSEC, no-log e no-filter
require_dnssec = true
require_nofilter = false
require_nolog = true

# Cache local
cache = true
cache_size = 4096
cache_min_ttl = 2400
cache_max_ttl = 86400

# Desabilitar download automático de listas públicas
# (queremos APENAS o NextDNS)
# Comente ou remova as seções [sources] se existirem:
# [sources]
#   [sources.'public-resolvers']
#     ...
#   [sources.'relays']
#     ...

# Servidor estático com seu stamp
[static]
  [static.'nextdns']
  stamp = 'sdns://AgMAAAAAAAAAAAAADmRucy5uZXh0ZG5zLmlvBy9hYmMxMjM'
</code></pre>
<p>Substitua o stamp pelo gerado com seu ID real.</p>
<p>Sobre o cache: os valores acima são agressivos de propósito. <code>cache_min_ttl = 2400</code> (40 minutos) e <code>cache_max_ttl = 86400</code> (24 horas) reduzem significativamente o número de queries ao NextDNS. Se você está no plano free (300k queries/mês), isso faz diferença. Mesmo no plano pago, menos queries = menos latência para domínios frequentes.</p>
<h2>O inferno do systemd-resolved</h2>
<p>Se você está no Fedora, Ubuntu ou qualquer distro que use systemd-resolved, prepare-se: ele escuta na porta 53 por padrão e vai conflitar com o dnscrypt-proxy.</p>
<p>Verifique antes de qualquer coisa:</p>
<pre><code class="language-bash">ss -tlnp | grep ':53 '
</code></pre>
<p>Se aparecer <code>systemd-resolve</code> ouvindo na 53, você tem duas opções:</p>
<h3>Opção A: Desabilitar o systemd-resolved (recomendado)</h3>
<p>Se você quer controle total do DNS e não precisa do resolved para nada:</p>
<pre><code class="language-bash">sudo systemctl disable --now systemd-resolved
sudo rm /etc/resolv.conf
echo 'nameserver 127.0.0.1' | sudo tee /etc/resolv.conf
sudo chattr +i /etc/resolv.conf
</code></pre>
<p>O <code>chattr +i</code> torna o arquivo imutável. Sem isso, o NetworkManager vai sobrescrever o <code>resolv.conf</code> na primeira reconexão. Para editar futuramente: <code>sudo chattr -i /etc/resolv.conf</code>.</p>
<h3>Opção B: Convivência (dnscrypt-proxy em porta alternativa)</h3>
<p>Se por algum motivo precisa manter o resolved (integração com VPN corporativa, mDNS/Avahi, etc.):</p>
<p>No <code>dnscrypt-proxy.toml</code>:</p>
<pre><code class="language-toml">listen_addresses = ['127.0.0.1:5353']
</code></pre>
<p>No <code>/etc/systemd/resolved.conf</code>:</p>
<pre><code class="language-ini">[Resolve]
DNS=127.0.0.1#5353
DNSStubListener=yes
</code></pre>
<pre><code class="language-bash">sudo systemctl restart systemd-resolved
</code></pre>
<p>Funciona, mas adiciona uma camada desnecessária. O resolved vira um middleman que só repassa. A não ser que tenha um motivo concreto, vá com a Opção A.</p>
<h3>Nota para Arch com Hyprland / Window Managers</h3>
<p>Se você não usa NetworkManager e configura rede via <code>iwd</code>, <code>dhcpcd</code> ou manualmente, o systemd-resolved provavelmente nem está ativo. Verifique com <code>systemctl status systemd-resolved</code>. Se estiver inativo, não precisa fazer nada. Apenas garanta que o <code>/etc/resolv.conf</code> aponte para <code>127.0.0.1</code>.</p>
<h2>Persistência do resolv.conf no Fedora com NetworkManager</h2>
<p>O NetworkManager reescreve o <code>/etc/resolv.conf</code> a cada reconexão. Além do <code>chattr +i</code>, existe uma abordagem mais limpa: instruir o NetworkManager a não gerenciar DNS.</p>
<p>Crie o arquivo <code>/etc/NetworkManager/conf.d/no-dns.conf</code>:</p>
<pre><code class="language-ini">[main]
dns=none
</code></pre>
<pre><code class="language-bash">sudo systemctl restart NetworkManager
</code></pre>
<p>A partir daqui, o NetworkManager não toca no DNS. Seu <code>resolv.conf</code> com <code>nameserver 127.0.0.1</code> permanece intacto.</p>
<h2>Habilitando e iniciando</h2>
<pre><code class="language-bash">sudo systemctl enable --now dnscrypt-proxy.service
</code></pre>
<p>Verifique:</p>
<pre><code class="language-bash">systemctl status dnscrypt-proxy
journalctl -u dnscrypt-proxy -f
</code></pre>
<p>Nos logs, procure linhas indicando que o servidor <code>nextdns</code> foi validado. Algo como:</p>
<pre><code class="language-plaintext">[nextdns] OK (DoH) - rtt: XXms
</code></pre>
<p>Se aparecer erros de stamp ou servidor não encontrado, revise o stamp e verifique se não há servidores padrão habilitados competindo com a configuração estática.</p>
<h2>Validação</h2>
<pre><code class="language-bash"># Resolução via dnscrypt-proxy
dig @127.0.0.1 esli.blog

# Confirmar NextDNS ativo
curl -sL https://test.nextdns.io
</code></pre>
<p>O retorno do <code>test.nextdns.io</code> deve mostrar:</p>
<ul>
<li><p>Status: Connected (ou Using NextDNS)</p>
</li>
<li><p>Protocol: DoH</p>
</li>
</ul>
<p>Se retornar "not using NextDNS", revise:</p>
<ol>
<li><p>O stamp (path correto com <code>/SEU_ID</code>?)</p>
</li>
<li><p>O <code>server_names</code> aponta para o nome correto?</p>
</li>
<li><p>Algum servidor padrão ainda está habilitado nas sources?</p>
</li>
<li><p>O <code>resolv.conf</code> aponta para <code>127.0.0.1</code>?</p>
</li>
</ol>
<p>Teste também a filtragem. Acesse um domínio que deveria ser bloqueado pelas suas blocklists no NextDNS:</p>
<pre><code class="language-bash">dig @127.0.0.1 [algum-site.bloqueado]
</code></pre>
<p>Se retornar <code>0.0.0.0</code> ou <code>NXDOMAIN</code>, a filtragem está funcionando.</p>
<h2>Configurações avançadas opcionais</h2>
<h3>Anonymized DNS com relays</h3>
<p>Se quiser ir além e usar relays para que o NextDNS não veja seu IP (via Anonymized DoH), adicione ao <code>dnscrypt-proxy.toml</code>:</p>
<pre><code class="language-toml">[anonymized_dns]
routes = [
    { server_name='nextdns', via=['anon-relay-1', 'anon-relay-2'] }
]
</code></pre>
<p>Os relays disponíveis estão na lista de resolvers do dnscrypt-proxy. Isso adiciona latência, mas aumenta significativamente a privacidade. Se o NextDNS não deve saber de qual IP as queries vêm, essa é a forma.</p>
<h3>Blocklists locais</h3>
<p>O dnscrypt-proxy suporta blocklists próprias, independentes do NextDNS. No <code>dnscrypt-proxy.toml</code>:</p>
<pre><code class="language-toml">[blocked_names]
blocked_names_file = '/etc/dnscrypt-proxy/blocked-names.txt'
</code></pre>
<p>No arquivo <code>blocked-names.txt</code>, adicione domínios (um por linha, suporta wildcards):</p>
<pre><code class="language-plaintext">*.facebook.com
*.tiktok.com
ads.*
</code></pre>
<p>Isso funciona mesmo se o NextDNS estiver fora do ar. É uma camada adicional de filtragem local.</p>
<h3>Query logging para debug</h3>
<pre><code class="language-toml">[query_log]
file = '/var/log/dnscrypt-proxy/query.log'
format = 'tsv'
</code></pre>
<p>Crie o diretório antes:</p>
<pre><code class="language-bash">sudo mkdir -p /var/log/dnscrypt-proxy
sudo chown _dnscrypt-proxy:_dnscrypt-proxy /var/log/dnscrypt-proxy
</code></pre>
<p>O formato TSV facilita análise com <code>awk</code>, <code>cut</code> e companhia. Desligue em produção se privacidade for prioridade.</p>
<p>Meu dnscrypt-config.toml: <a href="https://github.com/Esl1h/dotfiles/blob/main/etc/dnscrypt-proxy/dnscrypt-proxy.toml">https://github.com/Esl1h/dotfiles/blob/main/etc/dnscrypt-proxy/dnscrypt-proxy.toml</a></p>
<h2>Resultado</h2>
<p>Mesmo stamp, mesma configuração do NextDNS, mesma proteção que você tem no Android (que será o tema do <a href="https://esli.blog.br/dns-criptografado-no-android-invizible-pro-e-alternativas">próximo artigo</a>). Suas queries DNS saem criptografadas, filtradas pelas mesmas blocklists, com analytics unificado no painel do NextDNS.</p>
<p>Seu provedor de internet que se contente em ver pacotes criptografados passando sem saber o que você está resolvendo.</p>
<hr />
<p>Outros artigos relacionados:</p>
<ul>
<li><p><a href="https://esli.blog.br/dnscrypt-dns-stamps-guia">DNSCrypt, DNS Stamps e DNS Criptografado: o guia que faltava</a></p>
</li>
<li><p><a href="https://esli.blog.br/privacidade-e-seguranca-2025">Privacidade e Segurança (2025)</a></p>
</li>
<li><p><a href="https://esli.blog.br/vpn-nao-e-o-suficiente">VPN não é o suficiente</a></p>
</li>
<li><p><a href="https://esli.blog.br/como-fugir-das-propaganda-na-internet">Como fugir das propagandas na Internet</a></p>
</li>
<li><p><a href="https://esli.blog.br/funcoes-avancadas-no-brave-browser">Usando o Brave, scriptlets, filter e wikiwand para melhor navegação</a></p>
</li>
</ul>
<p>Referências:</p>
<ul>
<li><p><a href="https://github.com/DNSCrypt/dnscrypt-proxy">https://github.com/DNSCrypt/dnscrypt-proxy</a></p>
</li>
<li><p><a href="https://github.com/DNSCrypt/dnscrypt-proxy/wiki/Configuration">https://github.com/DNSCrypt/dnscrypt-proxy/wiki/Configuration</a></p>
</li>
<li><p><a href="https://dnscrypt.info/stamps/">https://dnscrypt.info/stamps/</a></p>
</li>
<li><p><a href="https://my.nextdns.io">https://my.nextdns.io</a></p>
</li>
<li><p><a href="https://test.nextdns.io">https://test.nextdns.io</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[DNSCrypt, DNS Stamps e DNS Criptografado: o guia que faltava]]></title><description><![CDATA[Toda vez que você digita um endereço no navegador, seu dispositivo faz uma consulta DNS. Por padrão, essa consulta vai em texto puro para o resolver do seu provedor de internet. Aquele mesmo provedor ]]></description><link>https://esli.blog.br/dnscrypt-dns-stamps-e-dns-criptografado-o-guia-que-faltava</link><guid isPermaLink="true">https://esli.blog.br/dnscrypt-dns-stamps-e-dns-criptografado-o-guia-que-faltava</guid><category><![CDATA[dns]]></category><category><![CDATA[dnscrypt]]></category><category><![CDATA[https]]></category><category><![CDATA[TLS]]></category><category><![CDATA[criptografia]]></category><category><![CDATA[Segurança Digital]]></category><category><![CDATA[Privacidad]]></category><category><![CDATA[DNS over https]]></category><category><![CDATA[DNS-over-QUIC]]></category><category><![CDATA[DNS over TLS]]></category><category><![CDATA[privacy]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Tue, 31 Mar 2026 12:44:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/c919b12f-b360-4162-b44e-1aa52693cf9f.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Toda vez que você digita um endereço no navegador, seu dispositivo faz uma consulta DNS. Por padrão, essa consulta vai em texto puro para o resolver do seu provedor de internet. Aquele mesmo provedor que jura não vender seus dados mas coincidentemente exibe propaganda de coisas que você pesquisou minutos atrás.</p>
<p>Já falei sobre DNS e privacidade em outros artigos aqui no blog, como no <a href="https://esli.blog.br/privacidade-e-seguranca-2025">Privacidade e Segurança (2025)</a>, onde uso NextDNS em todos os dispositivos, e no <a href="https://esli.blog.br/como-fugir-das-propaganda-na-internet">Como fugir das propagandas na Internet</a>, onde mostro como o NextDNS funciona como camada de bloqueio e também o <a href="https://esli.blog.br/nao-confie-no-seu-provedor-de-internet">porque você não deve confiar no seu provedor de internet</a>.<br />Neste artigo, vou aprofundar no protocolo DNSCrypt, nos DNS Stamps e no ecossistema de DNS criptografado.</p>
<h2>DNS tradicional: o problema</h2>
<p>O DNS (Domain Name System) resolve nomes de domínio em endereços IP. Funciona como uma lista telefônica: você pede o número de <code>esli.blog</code> e recebe o IP do servidor. O problema é que essa "ligação" acontece sem criptografia. Qualquer pessoa no caminho (seu ISP, o administrador da rede do café, um atacante na mesma rede) consegue ver exatamente quais domínios você está resolvendo.</p>
<p>Isto é, superficialmente, como funciona o protocolo. O DNS foi projetado nos anos 80, quando a internet era um ambiente acadêmico e a ideia de privacidade na rede não existia.</p>
<h2>Os protocolos de DNS criptografado</h2>
<p>Com o tempo, surgiram vários protocolos para resolver esse problema. Cada um com abordagens diferentes.</p>
<h3>DoT (DNS-over-TLS)</h3>
<p>Encapsula as consultas DNS dentro de uma conexão TLS. Usa a porta 853, dedicada exclusivamente para esse fim. Padronizado na RFC 7858.</p>
<p>O fato de usar uma porta própria é uma faca de dois gumes: facilita a configuração, mas também facilita o bloqueio. Um administrador de rede (ou governo) pode simplesmente bloquear a porta 853 e acabou o DoT. O Android usa DoT nativamente na função "DNS Privado" desde a versão 9, o que popularizou o protocolo em dispositivos móveis.</p>
<h3>DoH (DNS-over-HTTPS)</h3>
<p>Encapsula as consultas DNS dentro de conexões HTTPS, usando a porta 443. Padronizado na RFC 8484.</p>
<p>A sacada é que o tráfego DoH se mistura com o tráfego HTTPS normal. Para bloquear DoH, seria necessário bloquear todo o HTTPS, o que inviabilizaria a navegação. Isso o torna mais resistente à censura, mas também mais difícil de monitorar em ambientes corporativos (onde monitoramento pode ser legítimo). Navegadores como Firefox e Chrome suportam DoH nativamente.</p>
<h3>DoQ (DNS-over-QUIC)</h3>
<p>Usa o protocolo QUIC (que por sua vez roda sobre UDP) para transportar consultas DNS. Padronizado na RFC 9250.</p>
<p>Mais recente, promete menor latência que DoT/DoH por eliminar o handshake TLS+TCP separado. Ainda com adoção limitada, mas providers como AdGuard DNS já suportam.</p>
<h3>DoH3 (DNS-over-HTTP/3)</h3>
<p>Similar ao DoQ, mas usando HTTP/3 como transporte. Como o HTTP/3 já usa QUIC, herda as mesmas vantagens de latência. Providers como DNS0 (fundado pelos co-fundadores do NextDNS) já suportam.</p>
<h3>ODoH (Oblivious DNS-over-HTTPS)</h3>
<p>Uma camada de anonimização sobre o DoH. Usa um proxy intermediário (relay) para que o resolver nunca veja o IP do cliente que fez a consulta. Padronizado na RFC 9230.</p>
<p>O conceito é semelhante ao Anonymized DNSCrypt (que veremos adiante): separar quem pergunta de quem responde.</p>
<h3>DNSCrypt</h3>
<p>E aqui é onde a conversa fica interessante.</p>
<h2>DNSCrypt: o protocolo que a indústria ignorou</h2>
<p>O DNSCrypt foi criado por Frank Denis (jedisct1), o mesmo autor do libsodium. Não é um "remendo" sobre outro protocolo. Foi projetado especificamente para proteger tráfego DNS.</p>
<p>O que ele faz:</p>
<p><strong>Autenticação do servidor.</strong> O cliente valida que está falando com o resolver legítimo usando a chave pública do provider. Sem depender de CAs (Certificate Authorities). Isso elimina toda a cadeia de confiança de TLS, que é um ponto de falha conhecido.</p>
<p><strong>Criptografia da query e resposta.</strong> Usa Curve25519 para troca de chaves e XSalsa20-Poly1305 (ou XChaCha20-Poly1305) para criptografia autenticada. Tudo baseado em criptografia de curva elíptica, sem depender de RSA ou da infraestrutura de certificados X.509.</p>
<p><strong>Anti-replay e anti-forgery.</strong> Cada query tem um nonce único. Respostas forjadas ou repetidas são detectadas e descartadas.</p>
<p><strong>Padding.</strong> As queries e respostas são preenchidas com dados aleatórios para dificultar análise de tráfego baseada no tamanho dos pacotes.</p>
<p>O protocolo roda sobre UDP (porta 443 por padrão) e opcionalmente TCP. É leve, rápido e não depende de infraestrutura de PKI.</p>
<p>O protocolo está em processo de padronização no IETF como Internet-Draft (draft-denis-dprive-dnscrypt-06, atualizado em abril de 2025).</p>
<h3>Por que a indústria ignorou?</h3>
<p>Google, Cloudflare, Apple, Microsoft, todos adotaram DoH e DoT. O DNSCrypt ficou de fora do mainstream. Não porque seja inferior tecnicamente, mas porque não tem uma megacorp por trás patrocinando a adoção. DoH usa HTTPS, que toda a infraestrutura web já suporta e o DNSCrypt exige implementação própria.</p>
<p>Resultado: o protocolo DNSCrypt em si tem adoção limitada entre os grandes providers. AdGuard DNS, Quad9 e CleanBrowsing suportam. NextDNS, Cloudflare e Google não suportam o protocolo DNSCrypt, apenas DoH e DoT.</p>
<p>Mas aqui entra a distinção crucial: <strong>o protocolo DNSCrypt é uma coisa, o software dnscrypt-proxy é outra.</strong></p>
<h3>dnscrypt-proxy: o canivete suíço</h3>
<p>O dnscrypt-proxy é a implementação de referência do cliente. Escrito em Go, roda em praticamente qualquer coisa: Linux, macOS, Windows, Android, roteadores com OpenWrt.</p>
<p>O ponto é que o dnscrypt-proxy não se limita ao protocolo DNSCrypt. Ele suporta:</p>
<ul>
<li><p>DNSCrypt v2</p>
</li>
<li><p>DoH (DNS-over-HTTPS)</p>
</li>
<li><p>ODoH (Oblivious DoH)</p>
</li>
<li><p>Anonymized DNSCrypt</p>
</li>
</ul>
<p>Então mesmo que um provider não suporte o protocolo DNSCrypt (como o NextDNS), você ainda pode usar o dnscrypt-proxy para se conectar via DoH. O software aceita stamps de qualquer protocolo suportado.</p>
<h3>Anonymized DNSCrypt: DNS sem rastreio</h3>
<p>O DNS criptografado resolve o problema de interceptação no caminho. Mas não resolve o problema do próprio resolver saber quem fez a consulta. Seu IP chega ao servidor junto com a query.</p>
<p>O Anonymized DNSCrypt resolve isso introduzindo relays. Funciona assim:</p>
<ol>
<li><p>O cliente criptografa a query para o <strong>resolver</strong> final (usando a chave pública do resolver).</p>
</li>
<li><p>Envia a query criptografada para um <strong>relay</strong>.</p>
</li>
<li><p>O relay não tem a chave do resolver, então não consegue ler o conteúdo. Ele apenas encaminha o pacote.</p>
</li>
<li><p>O resolver recebe a query, descriptografa, resolve e responde via relay.</p>
</li>
</ol>
<p>O relay sabe o IP do cliente, mas não sabe o conteúdo da query. O resolver sabe o conteúdo da query, mas só vê o IP do relay. Nenhum dos dois tem o quadro completo.</p>
<p>Isso é fundamentalmente diferente de usar Tor para DNS (que é lento e não foi projetado para isso) ou de confiar cegamente que o resolver é “no-log”.</p>
<p>A lista de relays disponíveis está no repositório oficial: <a href="https://github.com/DNSCrypt/dnscrypt-resolvers">https://github.com/DNSCrypt/dnscrypt-resolvers</a></p>
<h2>DNS Stamps: o QR Code do DNS</h2>
<p>Configurar DNS criptografado manualmente é chato. Você precisa informar protocolo, IP, porta, hostname, path (no caso de DoH), chave pública (no caso de DNSCrypt), e opcionalmente hashes de certificado. São vários campos, cada um com formato diferente dependendo do protocolo.</p>
<p>O DNS Stamp resolve isso codificando tudo em uma única string.</p>
<h3>Estrutura</h3>
<p>Um stamp começa com <code>sdns://</code> seguido de um payload em base64url. O primeiro byte do payload identifica o protocolo:</p>
<table>
<thead>
<tr>
<th>Byte</th>
<th>Protocolo</th>
</tr>
</thead>
<tbody><tr>
<td>0x00</td>
<td>Plain DNS</td>
</tr>
<tr>
<td>0x01</td>
<td>DNSCrypt</td>
</tr>
<tr>
<td>0x02</td>
<td>DoH</td>
</tr>
<tr>
<td>0x03</td>
<td>DoT</td>
</tr>
<tr>
<td>0x04</td>
<td>DoQ</td>
</tr>
<tr>
<td>0x05</td>
<td>ODoH target</td>
</tr>
<tr>
<td>0x81</td>
<td>Anonymized DNSCrypt relay</td>
</tr>
<tr>
<td>0x85</td>
<td>ODoH relay</td>
</tr>
</tbody></table>
<p>Depois do protocolo, o payload contém propriedades (DNSSEC, no-log, no-filter), endereço IP, hashes de certificado, hostname, path e opcionalmente IPs de bootstrap.</p>
<h3>Exemplo prático</h3>
<p>Um stamp DoH para o NextDNS com ID <code>abc123</code>:</p>
<pre><code class="language-plaintext">sdns://AgMAAAAAAAAAAAAADmRucy5uZXh0ZG5zLmlvBy9hYmMxMjM
</code></pre>
<p>Decodificando:</p>
<ul>
<li><p>Protocolo: 0x02 (DoH)</p>
</li>
<li><p>Hostname: dns.nextdns.io</p>
</li>
<li><p>Path: /abc123</p>
</li>
<li><p>No-log: sim</p>
</li>
<li><p>DNSSEC: sim</p>
</li>
</ul>
<h3>Gerando stamps</h3>
<p>O gerador oficial está em <a href="https://dnscrypt.info/stamps/">https://dnscrypt.info/stamps/</a> (anteriormente em <a href="https://stamps.dnscrypt.info">https://stamps.dnscrypt.info</a>). Você seleciona o protocolo, preenche os campos e o stamp é gerado automaticamente. Funciona no sentido inverso também: cole um stamp e ele decodifica os campos.</p>
<p>A especificação dos DNS Stamps está em processo de padronização no IETF (draft-denis-dns-stamps-00, julho de 2025), suportando DNSCrypt, DoH, DoT, DoQ e ODoH.</p>
<h3>Quem publica stamps nativamente?</h3>
<p>Nem todo provider facilita a vida. Alguns publicam stamps prontos na documentação, outros exigem que você gere manualmente.</p>
<table>
<thead>
<tr>
<th>Provider</th>
<th>Stamp na doc</th>
<th>Protocolos</th>
</tr>
</thead>
<tbody><tr>
<td>AdGuard DNS</td>
<td>Sim</td>
<td>DNSCrypt, DoH, DoT</td>
</tr>
<tr>
<td>Cloudflare</td>
<td>Sim (listado no dnscrypt-resolvers)</td>
<td>DoH</td>
</tr>
<tr>
<td>Quad9</td>
<td>Sim (listado no dnscrypt-resolvers)</td>
<td>DNSCrypt, DoH</td>
</tr>
<tr>
<td>CleanBrowsing</td>
<td>Sim (listado no dnscrypt-resolvers)</td>
<td>DNSCrypt, DoH</td>
</tr>
<tr>
<td>Mullvad DNS</td>
<td>Sim</td>
<td>DoH</td>
</tr>
<tr>
<td>Control D</td>
<td>Sim</td>
<td>DoH, DoT</td>
</tr>
<tr>
<td>DNS0</td>
<td>Sim</td>
<td>DoH, DoQ</td>
</tr>
<tr>
<td>NextDNS</td>
<td>Sim (Setup &gt; Linux &gt; DNSCrypt)</td>
<td>DoH (via stamp)</td>
</tr>
</tbody></table>
<p><strong>Correção importante sobre o NextDNS:</strong> diferente do que muitos pensam, o NextDNS <strong>fornece</strong> o stamp na página de Setup. Vá em <a href="https://my.nextdns.io">https://my.nextdns.io</a>, acesse Setup Guide, selecione Routers, e procure a seção DNSCrypt. O stamp já está gerado com seu config ID. Ele é um stamp DoH (não DNSCrypt nativo, pois o NextDNS não suporta o protocolo DNSCrypt).</p>
<p>Se preferir gerar manualmente ou adicionar um nome de dispositivo ao path, use o gerador em <a href="https://dnscrypt.info/stamps/">https://dnscrypt.info/stamps/</a> com os seguintes campos:</p>
<table>
<thead>
<tr>
<th>Campo</th>
<th>Valor</th>
</tr>
</thead>
<tbody><tr>
<td>Protocol</td>
<td>DNS-over-HTTPS</td>
</tr>
<tr>
<td>IP Address</td>
<td>(vazio)</td>
</tr>
<tr>
<td>Host name</td>
<td>dns.nextdns.io</td>
</tr>
<tr>
<td>Hashes</td>
<td>(vazio)</td>
</tr>
<tr>
<td>Path</td>
<td>/SEU_ID (ex: /abc123) ou /SEU_ID/nome-dispositivo</td>
</tr>
<tr>
<td>No logs</td>
<td>marcado</td>
</tr>
<tr>
<td>No filter</td>
<td>desmarcado</td>
</tr>
<tr>
<td>DNSSEC</td>
<td>marcado</td>
</tr>
</tbody></table>
<p>O path deve começar com <code>/</code>. Se o ID é <code>abc123</code>, o path é <code>/abc123</code>. Para identificar o dispositivo no painel, adicione um nome: <code>/abc123/fedora-desktop</code>.</p>
<p>A lista completa de resolvers com stamps prontos está no repositório oficial: <a href="https://github.com/DNSCrypt/dnscrypt-resolvers">https://github.com/DNSCrypt/dnscrypt-resolvers</a></p>
<p>O dnscrypt-proxy baixa essas listas automaticamente e permite selecionar servidores por nome, protocolo, localização, ou filtrar por propriedades como no-log e DNSSEC.</p>
<h2>Resumo dos protocolos</h2>
<table>
<thead>
<tr>
<th>Protocolo</th>
<th>Porta</th>
<th>Transporte</th>
<th>Resistência a censura</th>
<th>Depende de CA</th>
<th>Anonimização nativa</th>
</tr>
</thead>
<tbody><tr>
<td>Do53 (tradicional)</td>
<td>53</td>
<td>UDP/TCP</td>
<td>Nenhuma</td>
<td>Não</td>
<td>Não</td>
</tr>
<tr>
<td>DoT</td>
<td>853</td>
<td>TLS</td>
<td>Baixa (porta dedicada)</td>
<td>Sim</td>
<td>Não</td>
</tr>
<tr>
<td>DoH</td>
<td>443</td>
<td>HTTPS</td>
<td>Alta (mistura com HTTPS)</td>
<td>Sim</td>
<td>Não (ODoH sim)</td>
</tr>
<tr>
<td>DoQ</td>
<td>853/8853</td>
<td>QUIC</td>
<td>Média</td>
<td>Sim</td>
<td>Não</td>
</tr>
<tr>
<td>DNSCrypt</td>
<td>443*</td>
<td>UDP/TCP</td>
<td>Alta</td>
<td>Não (chave própria)</td>
<td>Sim (via relay)</td>
</tr>
</tbody></table>
<p>* Porta padrão 443, mas configurável.</p>
<h2>Próximos artigos</h2>
<p>Este artigo é o primeiro de uma série de três. No <a href="https://esli.blog.br/dnscrypt-proxy-no-linux-configurando-dns-criptografado">próximo artigo</a>, mostro como instalar e configurar o dnscrypt-proxy no Linux (Fedora e Arch) utilizando o NextDNS como resolver. No <a href="https://esli.blog.br/dnscrypt-android-invizible-pro-nextdns">terceiro</a>, a configuração no Android com o InviZible Pro e alternativas.</p>
<p>Se você ainda está utilizando o DNS do seu provedor, considere que ele provavelmente sabe mais sobre seus hábitos de navegação do que você gostaria. E se pudesse cobrar por cada consulta que bisbilhota, já teria financiado uma ida à lua.</p>
<hr />
<p>Outros artigos relacionados no blog:</p>
<ul>
<li><p><a href="https://esli.blog.br/privacidade-e-seguranca-2025">Privacidade e Segurança (2025)</a></p>
</li>
<li><p><a href="https://esli.blog.br/vpn-nao-e-o-suficiente">VPN não é o suficiente</a></p>
</li>
<li><p><a href="https://esli.blog.br/como-fugir-das-propaganda-na-internet">Como fugir das propagandas na Internet</a></p>
</li>
<li><p><a href="https://esli.blog.br/qual-melhor-navegador">Qual melhor navegador</a></p>
</li>
<li><p><a href="https://esli.blog.br/comandos-linux-para-analise-de-redes-guia-completo-por-camada-da-tabela-osi">Guia de Comandos Linux para Redes (modelo OSI)</a></p>
</li>
</ul>
<p>Referências:</p>
<ul>
<li><p><a href="https://dnscrypt.info/">https://dnscrypt.info/</a></p>
</li>
<li><p><a href="https://dnscrypt.info/stamps-specifications/">https://dnscrypt.info/stamps-specifications/</a></p>
</li>
<li><p><a href="https://github.com/DNSCrypt/dnscrypt-proxy">https://github.com/DNSCrypt/dnscrypt-proxy</a></p>
</li>
<li><p><a href="https://github.com/DNSCrypt/dnscrypt-resolvers">https://github.com/DNSCrypt/dnscrypt-resolvers</a></p>
</li>
<li><p><a href="https://www.ietf.org/archive/id/draft-denis-dns-stamps-00.html">https://www.ietf.org/archive/id/draft-denis-dns-stamps-00.html</a></p>
</li>
<li><p><a href="https://www.cloudflare.com/learning/dns/dns-over-tls/">https://www.cloudflare.com/learning/dns/dns-over-tls/</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Mullvad: privacidade sem marketing, sem conta e sem desculpas]]></title><description><![CDATA[Num mundo onde todo serviço de VPN patrocina YouTuber e promete “anonimato militar”, a Mullvad simplesmente entrega o que promete e fica quieta.
O que entregam:
Gratuitos (sem assinatura)

DNS — resol]]></description><link>https://esli.blog.br/mullvad-privacidade-sem-marketing-sem-conta-e-sem-desculpas</link><guid isPermaLink="true">https://esli.blog.br/mullvad-privacidade-sem-marketing-sem-conta-e-sem-desculpas</guid><category><![CDATA[vpn]]></category><category><![CDATA[mullvad]]></category><category><![CDATA[@mullvad browser ]]></category><category><![CDATA[Browsers]]></category><category><![CDATA[tor]]></category><category><![CDATA[dns]]></category><category><![CDATA[privacy]]></category><category><![CDATA[Security]]></category><category><![CDATA[anonymity]]></category><category><![CDATA[wireguard]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Mon, 30 Mar 2026 16:46:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/9406b97c-9d33-43b5-ab21-ee6b4afb2039.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Num mundo onde todo serviço de VPN patrocina YouTuber e promete “anonimato militar”, a Mullvad simplesmente entrega o que promete e fica quieta.</p>
<p>O que entregam:</p>
<p><strong>Gratuitos (sem assinatura)</strong></p>
<ol>
<li><p><strong>DNS</strong> — resolvedores DoH/DoT com 6 perfis de filtragem</p>
</li>
<li><p><strong>Mullvad Browser</strong> — navegador anti-fingerprinting com Tor Project</p>
</li>
<li><p><strong>Connection Check</strong> — ferramenta web (<code>mullvad.net/check</code>) e API (<code>am.i.mullvad.net/json</code>) para verificar IP, localização, DNS leaks e status da conexão. Funciona para qualquer VPN, não só Mullvad.</p>
</li>
<li><p><strong>Código-fonte aberto</strong> — todo o código do app (desktop/mobile) e browser está no GitHub sob GPLv3</p>
</li>
<li><p><strong>Acesso via .onion</strong> — site completo acessível pela rede Tor</p>
</li>
</ol>
<p><strong>Descontinuados:</strong></p>
<ol>
<li><strong>Mullvad Leta</strong> — motor de busca proxy (Google/Brave Search). Foi descontinuado. <a href="https://leta.mullvad.net/">Mullvad</a> Inicialmente requeria conta paga, tornou-se gratuito e aberto a todos em março de 2025 <a href="https://forum.vivaldi.net/topic/113035/mullvad-leta-search-engine">Vivaldi</a>, e foi posteriormente desligado.</li>
</ol>
<p><strong>Pago (€5/mês):</strong></p>
<ul>
<li>VPN (WireGuard, multihop, DAITA, anti-censura, kill switch, split tunneling, túneis pós-quânticos).</li>
</ul>
<h2>O que é a Mullvad</h2>
<p>Mullvad significa "toupeira" em sueco. O nome já entrega a proposta: cavar um túnel e sumir. A empresa foi fundada em 2009 por Daniel Berntsson e Fredrik Strömberg em Gotemburgo, Suécia, sob a empresa Amagicom AB. Desde o início, a ideia era oferecer um serviço de VPN que não exigisse e-mail, nome, telefone ou qualquer dado pessoal para funcionar.</p>
<p>Enquanto a concorrência inteira entrava numa corrida de quem gritava mais alto sobre privacidade (e ao mesmo tempo pedia seu CPF no cadastro), a Mullvad gerava um número de conta aleatório de 16 dígitos e pronto. Esse é seu login. Não existe "recuperar senha", não existe "esqueci meu e-mail". Perdeu o número, perdeu o acesso. Simples, brutal e coerente.</p>
<p>Em abril de 2023, a polícia sueca apareceu no escritório da Mullvad com um mandado de busca e apreensão querendo dados de clientes. Saíram de mãos vazias. Não porque a Mullvad se recusou a cooperar, mas porque não havia dados para entregar. A política de no-log não era só marketing, realmente faz parte arquitetura.</p>
<h2>Filosofia</h2>
<p>A Mullvad opera com alguns princípios raros no mercado de VPN:</p>
<ol>
<li><p><strong>Sem contas identificáveis.</strong> Número aleatório. Sem e-mail, sem nome.</p>
</li>
<li><p><strong>Preço único e fixo.</strong> Sem planos anuais com desconto manipulativo, sem "oferta por tempo limitado". O mesmo valor desde 2009.</p>
</li>
<li><p><strong>Código aberto.</strong> Clientes para todas as plataformas com código no GitHub.</p>
</li>
<li><p><strong>Auditorias independentes.</strong> Realizadas por Cure53, Assured AB, X41 D-Sec, entre outros. Publicadas e acessíveis.</p>
</li>
<li><p><strong>Aceita pagamento anônimo.</strong> Dinheiro pelo correio (sim, você coloca euros num envelope e manda pra Suécia), Bitcoin, Bitcoin Cash, Monero, e cartão.</p>
</li>
<li><p><strong>Sem programa de afiliados.</strong> Nenhum YouTuber vai te oferecer "código PRIVACIDADE10" pra Mullvad. Eles simplesmente não fazem isso.</p>
</li>
<li><p><strong>Sem renovação automática.</strong> Você não "assina" a Mullvad. Você adiciona tempo à conta. Acabou, acabou. Sem surpresas no cartão.</p>
</li>
</ol>
<p>Essa última é a que mais me diverte. A ausência total de marketing agressivo num mercado que é basicamente sustentado por marketing agressivo. Enquanto a NordVPN e a Surfshark brigam pra ver quem patrocina mais podcasters e youtubers, a Mullvad está lá no canto, fazendo o trabalho.</p>
<h2>VPN</h2>
<h3>O que você recebe</h3>
<p>O serviço de VPN é o produto principal. Desde janeiro de 2026, a Mullvad opera exclusivamente com o protocolo WireGuard. O suporte a OpenVPN foi completamente removido após um período de transição que começou em novembro de 2024. A decisão faz sentido: WireGuard é mais rápido, mais leve, tem uma base de código drasticamente menor (o que significa menos superfície de ataque) e já era o protocolo padrão do app havia anos.</p>
<p>Com o foco exclusivo no WireGuard, a Mullvad pôde investir em funcionalidades avançadas:</p>
<p><strong>Multihop</strong> — entrada por um servidor, saída por outro. Separa o ponto que conhece sua origem do ponto que conhece seu destino.</p>
<p><strong>DAITA (Defense Against AI-guided Traffic Analysis)</strong> — mecanismo para dificultar análise de tráfego por machine learning. Adiciona padding e padrões de tráfego fictício para que um observador não consiga inferir o que você está fazendo dentro do túnel.</p>
<p><strong>Túneis pós-quânticos</strong> — proteção contra a possibilidade de que computadores quânticos futuros quebrem a criptografia usada na troca de chaves atual. A Mullvad implementa key exchange quantum-resistant sobre WireGuard.</p>
<p><strong>Anti-censura</strong> — para contornar bloqueios em redes restritivas, o app oferece Shadowsocks e UDP-over-TCP diretamente nas configurações. Substituem a necessidade do antigo bridge mode com OpenVPN.</p>
<h3>Servidores</h3>
<p>A Mullvad mantém cerca de 580 servidores em 50 países, distribuídos em 90 cidades. Não é a maior rede do mercado, longe disso. Mas a filosofia é diferente: boa parte da infraestrutura é composta por servidores próprios (bare-metal), não alugados em cloud. Todos os servidores rodam em RAM (diskless), o que significa que um reboot apaga tudo. Isso reduz a superfície de ataque e a dependência de terceiros.</p>
<p>A lista completa de servidores e o status em tempo real ficam em: <a href="https://mullvad.net/en/servers">https://mullvad.net/en/servers</a></p>
<h3>Limite de dispositivos</h3>
<p>Cada conta permite até 5 conexões simultâneas. Simples, sem tiers, sem upsell para "plano família".</p>
<h3>Instalação no Linux</h3>
<p><strong>No Arch (e derivados):</strong></p>
<pre><code class="language-plaintext">yay -S mullvad-vpn
</code></pre>
<p><strong>No Fedora:</strong></p>
<pre><code class="language-plaintext">sudo dnf config-manager addrepo --from-repofile=https://repository.mullvad.net/rpm/stable/mullvad.repo
sudo dnf install mullvad-vpn
</code></pre>
<p><strong>No Debian/Ubuntu via repositório:</strong></p>
<pre><code class="language-plaintext">sudo apt install curl
sudo curl -fsSLo /usr/share/keyrings/mullvad-keyring.asc https://repository.mullvad.net/deb/mullvad-keyring.asc
echo "deb [signed-by=/usr/share/keyrings/mullvad-keyring.asc arch=$( dpkg --print-architecture )] https://repository.mullvad.net/deb/stable stable main" | sudo tee /etc/apt/sources.list.d/mullvad.list
sudo apt update
sudo apt install mullvad-vpn
</code></pre>
<p>A versão mais recente no momento da escrita é a <strong>2026.1</strong>, que já usa Wayland por padrão no Linux (com fallback para X11).</p>
<p>Existe a versão com GUI (<code>mullvad-vpn</code>) e sem GUI (<code>mullvad-vpn-cli</code>). Para quem roda Hyprland ou qualquer WM sem tray nativa, a CLI resolve bem:</p>
<pre><code class="language-plaintext">mullvad account login 1234567890123456
mullvad relay set location br sao
mullvad connect
mullvad status
</code></pre>
<p>Nota para quem usa Fedora com GNOME ou KDE: a partir da versão 2026.1, o ícone na tray pode exigir a extensão AppIndicator e o pacote <code>libappindicator-gtk3</code>.</p>
<p>Para WireGuard puro, sem o client da Mullvad, é possível gerar configurações diretamente pelo site: <a href="https://mullvad.net/en/account/wireguard-config">https://mullvad.net/en/account/wireguard-config</a></p>
<p>Isso gera um arquivo <code>.conf</code> que você importa direto no <code>wg-quick</code> ou no NetworkManager:</p>
<pre><code class="language-plaintext">sudo wg-quick up /etc/wireguard/mullvad-br-sao.conf
</code></pre>
<h3>Multihop com WireGuard</h3>
<p>O multihop encadeia dois servidores: o tráfego entra por um e sai por outro. Útil pra quem quer uma camada extra de separação entre entrada e saída.</p>
<p>Via CLI:</p>
<pre><code class="language-plaintext">mullvad relay set tunnel wireguard --entry-location se got
mullvad relay set location us nyc
mullvad connect
</code></pre>
<p>Nesse exemplo, o tráfego entra pela Suécia (Gotemburgo) e sai pelos EUA (Nova York).</p>
<h3>Kill Switch</h3>
<p>O kill switch vem habilitado por padrão. Se a conexão VPN cair, todo o tráfego de rede é bloqueado até reconectar. Sem vazamentos. Sem "ah, mas eu queria acessar a rede local". Se quiser ajustar:</p>
<pre><code class="language-plaintext">mullvad lockdown-mode set on
mullvad lan set allow
</code></pre>
<h3>Split Tunneling</h3>
<p>Permite que processos específicos ignorem o túnel VPN:</p>
<pre><code class="language-plaintext">mullvad split-tunnel add 1234  # PID do processo
</code></pre>
<p>No Linux, funciona via cgroups. Não é o método mais elegante do mundo, mas funciona.</p>
<h3>Anti-censura</h3>
<p>Desde a remoção do OpenVPN, a Mullvad oferece métodos de ofuscação diretamente no WireGuard:</p>
<pre><code class="language-plaintext">mullvad anti-censorship set udp-over-tcp --port 443   # simula OpenVPN sobre TCP
mullvad anti-censorship set shadowsocks              # simula o antigo bridge mode
mullvad anti-censorship set automatic                # tenta automaticamente se WireGuard puro falhar
</code></pre>
<p>A opção <code>automatic</code> é a mais prática: tenta conexão direta primeiro e escala para ofuscação se necessário.</p>
<h2>Preço</h2>
<p>5 euros por mês. Sempre. Desde 2009. Sem desconto anual, sem Black Friday, sem "plano de 3 anos que parece barato até você fazer a conta". Um mês custa 5 euros. Doze meses custam 60 euros. A matemática é simples e honesta.</p>
<p>O único desconto que existe é de <strong>10% para pagamento em criptomoedas</strong> (Bitcoin, Bitcoin Cash e Monero), devido a taxas menores de processamento.</p>
<p>Formas de pagamento: cartão de crédito, PayPal, Bitcoin, Bitcoin Cash, Monero, transferência bancária, Swish (Suécia), EPS transfer, Bancontact, iDEAL/Wero, Przelewy24, e dinheiro físico pelo correio.</p>
<p>Garantia de devolução: <strong>14 dias</strong> (exceto para pagamentos em dinheiro e criptomoedas).</p>
<p>Página da conta: <a href="https://mullvad.net/en/account">https://mullvad.net/en/account</a></p>
<h3>Mullvad e a Mozilla VPN</h3>
<p>Um ponto que muita gente não sabe: a Mozilla VPN (aquela integrada ao ecossistema Firefox) usa a infraestrutura de servidores da Mullvad por baixo. Se você já assina a Mullvad, a Mozilla VPN é redundante. Se está avaliando a Mozilla VPN, saiba que os servidores WireGuard que ela usa são os mesmos da Mullvad, mas com outra camada de billing e interface.</p>
<h2>Mullvad Browser</h2>
<p>Em abril de 2023, a Mullvad se juntou ao Tor Project para lançar o Mullvad Browser. A ideia é simples e genial: pegar a engenharia anti-fingerprinting do Tor Browser, remover a rede Tor e entregar um navegador que funciona com VPN (ou sem VPN) mas que torna todos os usuários indistinguíveis entre si.</p>
<p>O Tor Browser já é o padrão ouro em anti-fingerprinting. O problema é que muita gente quer essa proteção mas não quer (ou não precisa) rotear tudo pela rede Tor, que é mais lenta e levanta flags em vários serviços. O Mullvad Browser resolve isso.</p>
<h3>O que muda na prática</h3>
<p>Todos os usuários do Mullvad Browser têm a mesma fingerprint. Mesmas fontes, mesma resolução reportada, mesmas configurações. O objetivo é criar uma "multidão" onde cada indivíduo é indistinguível. É o conceito de <em>crowd anonymity</em> aplicado ao navegador.</p>
<p>Ele já vem com:</p>
<ul>
<li><p>uBlock Origin pré-instalado</p>
</li>
<li><p>Modo privado por padrão (sem histórico persistente)</p>
</li>
<li><p>Letterboxing (a área útil do browser é padronizada para evitar fingerprinting por resolução)</p>
</li>
<li><p>Proteção contra fingerprinting de canvas, WebGL, AudioContext</p>
</li>
<li><p>Sem telemetria</p>
</li>
</ul>
<h3>Ciclo de atualização</h3>
<p>O Mullvad Browser é baseado no Firefox ESR (Extended Support Release), o que garante estabilidade. A partir de 2026, o canal Alpha passou a seguir o Firefox Rapid Release em vez do ESR, com atualizações a cada quatro semanas. O canal Stable continua no ESR. O Alpha também passou a estar disponível para Linux ARM.</p>
<h3>Relação com o Tor Project</h3>
<p>O Mullvad Browser é mantido pelo Tor Project com financiamento da Mullvad. Usa a mesma base do Tor Browser (Firefox ESR com patches), mas sem o proxy SOCKS da rede Tor. É literalmente o Tor Browser para quem não quer usar Tor.</p>
<p>Isso não é concorrência ao Tor Browser. São ferramentas complementares:</p>
<table>
<thead>
<tr>
<th>Cenário</th>
<th>Ferramenta recomendada</th>
</tr>
</thead>
<tbody><tr>
<td>Precisa de anonimato forte contra vigilância estatal</td>
<td>Tor Browser</td>
</tr>
<tr>
<td>Quer anti-fingerprinting com velocidade normal de internet</td>
<td>Mullvad Browser + VPN</td>
</tr>
<tr>
<td>Quer anti-fingerprinting sem VPN</td>
<td>Mullvad Browser sozinho</td>
</tr>
<tr>
<td>Navegação comum com alguma privacidade</td>
<td>Firefox com hardening ou Brave</td>
</tr>
</tbody></table>
<p>Download: <a href="https://mullvad.net/en/browser">https://mullvad.net/en/browser</a></p>
<p>Disponível para Linux, Windows e macOS. No Linux, vem como tarball. Extrai, roda, sem instalação no sistema.</p>
<h2>DNS</h2>
<p>Aqui a Mullvad entrega bastante coisa gratuitamente. Você não precisa ser assinante da VPN para usar os servidores DNS deles.</p>
<h3>O que é DNS e por que você deveria se importar</h3>
<p>O DNS (Domain Name System) é o sistema que traduz nomes de domínio como <code>esli.blog.br</code> em endereços IP. Toda vez que você acessa qualquer site, uma consulta DNS acontece antes de tudo. Se essa consulta não é criptografada, seu provedor de internet (e qualquer um no caminho) sabe exatamente quais sites você está acessando, mesmo que o conteúdo em si esteja criptografado via HTTPS.</p>
<p>A Mullvad oferece resolvedores DNS gratuitos com criptografia e diferentes níveis de filtragem. Não registram logs.</p>
<h3>Tipos de DNS oferecidos</h3>
<p>Todos suportam DNS over HTTPS (DoH) e DNS over TLS (DoT), sem logging.</p>
<table>
<thead>
<tr>
<th>Perfil</th>
<th>Filtragem</th>
<th>DoH URL</th>
<th>IP (sem criptografia)</th>
</tr>
</thead>
<tbody><tr>
<td>Sem filtro</td>
<td>Nenhuma</td>
<td><code>https://dns.mullvad.net/dns-query</code></td>
<td>194.242.2.2</td>
</tr>
<tr>
<td>Bloqueio de ads</td>
<td>Anúncios</td>
<td><code>https://adblock.dns.mullvad.net/dns-query</code></td>
<td>194.242.2.3</td>
</tr>
<tr>
<td>Ads + tracking</td>
<td>Anúncios e rastreadores</td>
<td><code>https://base.dns.mullvad.net/dns-query</code></td>
<td>194.242.2.4</td>
</tr>
<tr>
<td>Ads + tracking + malware</td>
<td>Ads, trackers e domínios maliciosos</td>
<td><code>https://extended.dns.mullvad.net/dns-query</code></td>
<td>194.242.2.5</td>
</tr>
<tr>
<td>Bloqueio completo</td>
<td>Ads, trackers, malware, redes sociais e gambling</td>
<td><code>https://all.dns.mullvad.net/dns-query</code></td>
<td>194.242.2.6</td>
</tr>
<tr>
<td>Família</td>
<td>Tudo acima + conteúdo adulto</td>
<td><code>https://family.dns.mullvad.net/dns-query</code></td>
<td>194.242.2.7</td>
</tr>
</tbody></table>
<p>Documentação completa: <a href="https://mullvad.net/en/help/dns-over-https-and-dns-over-tls">https://mullvad.net/en/help/dns-over-https-and-dns-over-tls</a></p>
<h3>Qual perfil escolher</h3>
<p>Se você nunca configurou um DNS alternativo antes e quer algo prático: comece com o <strong>base</strong> (<code>194.242.2.4</code>). Ele bloqueia anúncios e rastreadores sem quebrar sites. Se quiser proteção adicional contra domínios maliciosos, suba para o <strong>extended</strong>. O <strong>all</strong> pode quebrar funcionalidades de redes sociais embeddadas em sites, então use com consciência.</p>
<h3>Configurando no systemd-resolved</h3>
<pre><code class="language-plaintext">sudo mkdir -p /etc/systemd/resolved.conf.d
cat &lt;&lt; 'EOF' | sudo tee /etc/systemd/resolved.conf.d/mullvad-dns.conf
[Resolve]
DNS=194.242.2.4#base.dns.mullvad.net
DNSOverTLS=yes
Domains=~.
EOF
sudo systemctl restart systemd-resolved
resolvectl status
</code></pre>
<h3>Configurando via NetworkManager</h3>
<pre><code class="language-plaintext">nmcli connection modify "SuaConexao" ipv4.dns "194.242.2.4"
nmcli connection modify "SuaConexao" ipv4.ignore-auto-dns yes
nmcli connection down "SuaConexao" &amp;&amp; nmcli connection up "SuaConexao"
</code></pre>
<h3>DNS no Mullvad Browser</h3>
<p>O Mullvad Browser usa o DoH da Mullvad por padrão. Não precisa configurar nada. Se quiser trocar o perfil de filtragem, altere nas configurações de rede do browser (<code>about:preferences#general</code> na seção Network Settings).</p>
<h3>DNS e a Mullvad VPN</h3>
<p>Quando você está conectado à VPN da Mullvad, o DNS é automaticamente roteado pelos servidores deles dentro do túnel. Isso evita DNS leaks. Se quiser trocar o perfil de filtragem dentro da VPN:</p>
<pre><code class="language-plaintext">mullvad dns set default --block-ads --block-trackers --block-malware
</code></pre>
<p>Para verificar:</p>
<pre><code class="language-plaintext">mullvad dns get
</code></pre>
<h2>Integração com o Brave</h2>
<p>O Brave <strong>não</strong> usa a Mullvad como backend de VPN. O Brave Firewall + VPN é powered by Guardian, uma empresa americana, e é um produto completamente separado, com outra infraestrutura, outro preço (US\(9.99/mês ou US\)99.99/ano), e até outra jurisdição (EUA, dentro do Five Eyes, o que não é exatamente ideal para um serviço de privacidade).</p>
<p>A relação entre Brave e Mullvad é mais limitada e indireta: ambos compartilham valores de privacidade e o Brave permite configuração de DNS customizado, o que torna trivial usar os resolvedores da Mullvad sem pagar nada.</p>
<p>Para configurar o DoH da Mullvad no Brave:</p>
<p><code>brave://settings/security</code> → seção "Usar DNS seguro" → "Personalizado" → inserir:</p>
<pre><code class="language-plaintext">https://base.dns.mullvad.net/dns-query
</code></pre>
<p>Troque <code>base</code> por <code>adblock</code>, <code>extended</code>, <code>all</code> ou <code>family</code> conforme o nível de filtragem desejado.</p>
<h2>Mullvad e Tor: a relação completa</h2>
<p>A relação entre Mullvad e Tor vai além do browser. Existem alguns pontos de conexão:</p>
<h3>Mullvad Browser</h3>
<p>Parceria direta. Tor Project desenvolve, Mullvad financia. Já coberto acima.</p>
<h3>VPN + Tor</h3>
<p>Usar VPN antes do Tor (VPN como entrada) tem prós e contras:</p>
<p><strong>Prós:</strong></p>
<ul>
<li><p>Seu ISP não sabe que você está usando Tor</p>
</li>
<li><p>O nó de entrada do Tor vê o IP da VPN, não o seu</p>
</li>
</ul>
<p><strong>Contras:</strong></p>
<ul>
<li><p>A Mullvad sabe que você está usando Tor (já que seu tráfego passa pelo túnel)</p>
</li>
<li><p>Adiciona um ponto de confiança na cadeia</p>
</li>
</ul>
<p>A Mullvad não bloqueia Tor e não interfere no tráfego. Funciona de forma transparente.</p>
<h3>Pagamento via Tor</h3>
<p>O site da Mullvad é acessível via .onion:</p>
<p><code>http://o54hon2e2vj6c7m3aqqu6uyece65by3vgoez7kfzrhqsitv2bvqd.onion</code></p>
<p>Você pode gerar uma conta, adicionar tempo e configurar tudo sem nunca sair da rede Tor.</p>
<h2>Auditorias de segurança</h2>
<p>A Mullvad é uma das VPNs mais auditadas do mercado. As auditorias são feitas por firmas independentes e os relatórios são publicados integralmente. Algumas das mais recentes incluem avaliações da Cure53, Assured AB, e X41 D-Sec, cobrindo infraestrutura, aplicativo, política de logs e implementação WireGuard. A auditoria mais recente da implementação WireGuard não encontrou vulnerabilidades críticas.</p>
<p>Todos os relatórios ficam disponíveis no blog oficial: <a href="https://mullvad.net/en/blog">https://mullvad.net/en/blog</a></p>
<h2>Apps e links</h2>
<table>
<thead>
<tr>
<th>Plataforma</th>
<th>Link</th>
</tr>
</thead>
<tbody><tr>
<td>Linux (deb/rpm)</td>
<td><a href="https://mullvad.net/en/download/linux">https://mullvad.net/en/download/linux</a></td>
</tr>
<tr>
<td>Windows</td>
<td><a href="https://mullvad.net/en/download/windows">https://mullvad.net/en/download/windows</a></td>
</tr>
<tr>
<td>macOS</td>
<td><a href="https://mullvad.net/en/download/macos">https://mullvad.net/en/download/macos</a></td>
</tr>
<tr>
<td>Android</td>
<td><a href="https://mullvad.net/en/download/android">https://mullvad.net/en/download/android</a></td>
</tr>
<tr>
<td>iOS</td>
<td><a href="https://mullvad.net/en/download/ios">https://mullvad.net/en/download/ios</a></td>
</tr>
<tr>
<td>Mullvad Browser</td>
<td><a href="https://mullvad.net/en/browser">https://mullvad.net/en/browser</a></td>
</tr>
<tr>
<td>GitHub</td>
<td><a href="https://github.com/mullvad">https://github.com/mullvad</a></td>
</tr>
<tr>
<td>Status dos servidores</td>
<td><a href="https://mullvad.net/en/servers">https://mullvad.net/en/servers</a></td>
</tr>
<tr>
<td>Verificar conexão</td>
<td><a href="https://mullvad.net/en/check">https://mullvad.net/en/check</a></td>
</tr>
<tr>
<td>DNS</td>
<td><a href="https://mullvad.net/en/help/dns-over-https-and-dns-over-tls">https://mullvad.net/en/help/dns-over-https-and-dns-over-tls</a></td>
</tr>
</tbody></table>
<p>O app está disponível também no F-Droid (Android) e na App Store (iOS).</p>
<h2>Verificando se está tudo funcionando</h2>
<p>Depois de conectar a VPN, o teste rápido:</p>
<pre><code class="language-plaintext">curl -s https://am.i.mullvad.net/json | python3 -m json.tool
</code></pre>
<p>Isso retorna seu IP, localização, se está conectado à Mullvad e se há DNS leaks.</p>
<p>Pelo navegador: <a href="https://mullvad.net/en/check">https://mullvad.net/en/check</a></p>
<h2>O que a Mullvad não faz</h2>
<p>Vale ser honesto sobre as limitações:</p>
<ul>
<li><p><strong>Streaming:</strong> não desbloqueia Netflix, Disney+, Hulu, BBC iPlayer, e nem tenta. Se esse é seu caso de uso principal, procure outro serviço.</p>
</li>
<li><p><strong>Rede de servidores:</strong> ~580 servidores em 50 países é modesto comparado a NordVPN (6000+ em 100+ países) ou Proton VPN (milhares em 120+ países). Na prática, funciona bem para uso normal, mas não espere cobertura ampla na Ásia ou África.</p>
</li>
<li><p><strong>Interface:</strong> funcional, não bonita. Não tem mapa mundi interativo nem tutorial de onboarding. Assume que você sabe o que está fazendo.</p>
</li>
<li><p><strong>Suporte:</strong> apenas por e-mail. Sem chat ao vivo, sem telefone.</p>
</li>
<li><p><strong>Jurisdição:</strong> Suécia, que faz parte da aliança 14 Eyes. Na prática, a política de no-log e a arquitetura diskless mitigam o risco, mas é um fator a considerar no seu threat model.</p>
</li>
</ul>
<h2>Considerações</h2>
<p>A Mullvad não vai te mandar e-mail de "sentimos sua falta" porque nem sabe quem você é. Não vai aparecer no seu feed patrocinando um podcast. Não tem selo de "VPN mais rápida de 2024" dado por um site que recebe comissão de afiliado.</p>
<p>Mas faz o que promete. E no mercado de VPN, onde a maioria das empresas é basicamente uma operação de marketing com um proxy WireGuard por trás, isso vale mais do que qualquer selo.</p>
<p>Se privacidade é uma preocupação real e não só um checkbox no seu threat model, a Mullvad é provavelmente a escolha mais coerente que existe hoje.</p>
]]></content:encoded></item><item><title><![CDATA[Não confie no seu provedor de internet]]></title><description><![CDATA[Seu provedor de internet sabe mais sobre você do que a maioria dos seus amigos. Cada site que você acessa, cada busca que faz, cada serviço que usa. Tudo passa pelos servidores dele. E se você acha qu]]></description><link>https://esli.blog.br/nao-confie-no-seu-provedor-de-internet</link><guid isPermaLink="true">https://esli.blog.br/nao-confie-no-seu-provedor-de-internet</guid><category><![CDATA[dns]]></category><category><![CDATA[vpn]]></category><category><![CDATA[TLS]]></category><category><![CDATA[https]]></category><category><![CDATA[SPYING]]></category><category><![CDATA[isp]]></category><category><![CDATA[PSA]]></category><category><![CDATA[privacy]]></category><category><![CDATA[anonymity]]></category><category><![CDATA[Security]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Sun, 29 Mar 2026 23:42:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/0a10b6e2-e2dc-4e1d-a73e-fee92b2fbcbb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Seu provedor de internet sabe mais sobre você do que a maioria dos seus amigos. Cada site que você acessa, cada busca que faz, cada serviço que usa. Tudo passa pelos servidores dele. E se você acha que ele trata esses dados com o devido cuidado... este artigo é para você.</p>
<p>Vou mostrar por que o ISP (Internet Service Provider) é o elo mais perigoso da sua cadeia de conectividade, casos reais em que provedores no Brasil e no mundo falharam (ou agiram contra seus próprios clientes) e, principalmente, o que fazer para reduzir drasticamente o poder que ele tem sobre a sua vida digital.</p>
<h2>O problema: seu ISP vê tudo</h2>
<p>Quando você digita um endereço no navegador, a primeira coisa que acontece é uma consulta DNS. Por padrão, essa consulta vai para o servidor DNS do seu provedor. Em texto plano. Sem criptografia. Ele sabe exatamente quais domínios você resolve, quando e com qual frequência.</p>
<p>Mesmo com HTTPS (que criptografa o conteúdo), o provedor ainda enxerga:</p>
<ul>
<li><p>O domínio que você está acessando (via SNI no TLS handshake)</p>
</li>
<li><p>Os IPs de destino e origem</p>
</li>
<li><p>O volume de dados trafegados</p>
</li>
<li><p>Os horários de acesso</p>
</li>
<li><p>O tipo de protocolo utilizado</p>
</li>
</ul>
<p>Com essas informações, dá para construir um perfil comportamental completo. E muitos provedores fazem exatamente isso.</p>
<h2>Casos reais: quando a confiança quebrou</h2>
<h3>Brasil: envenenamento de DNS na Oi e GVT</h3>
<p>Em 2011, servidores DNS da Oi Velox e GVT foram envenenados. Ao acessar sites como o Google, os usuários eram induzidos a baixar um executável malicioso chamado <code>Google_Setup.exe</code>. Os arquivos continham rotinas de captura de dados. Na época, a Oi tinha cerca de 6 milhões de assinantes e a GVT, 1,4 milhão. A Oi negou o ataque. Padrão.</p>
<h3>Brasil: dados de 28 milhões de clientes da NET/Claro à venda</h3>
<p>Em 2020, um hacker colocou à venda em fórum da dark web dados de quase 28 milhões de clientes da antiga NET (Claro), incluindo nome completo, CPF, data de nascimento, email, telefone e endereço. A Claro informou que “não foram encontradas evidências” de que os dados fossem da empresa. Padrão, de novo.</p>
<h3>Brasil: Claro, TIM, Vivo e Oi compartilhando dados de forma ilícita</h3>
<p>O Ministério Público da Bahia acionou as quatro maiores operadoras por "vazamento de dados" e compartilhamento ilícito de informações pessoais, obrigando-as a obter consentimento antes de continuar tratando dados dos clientes. O relatório "Quem defende seus dados?" do InternetLab revelou que nenhuma operadora brasileira sequer avisa o usuário quando entrega dados para autoridades.</p>
<h3>Brasil: Anatel investiga Vivo, Claro e TIM por espionagem</h3>
<p>Em 2024, a Anatel abriu processos administrativos para apurar se Vivo, Claro e TIM sabiam de monitoramento indevido de dados de clientes e se deveriam ter notificado a agência. As operadoras disseram que só souberam pela imprensa. Se você confia nisso, eu tenho uns NFTs para te vender.</p>
<h3>EUA: Verizon e os supercookies</h3>
<p>A Verizon injetou silenciosamente um identificador único (X-UIDH) em todo o tráfego HTTP dos seus clientes mobile por dois anos. Esse "supercookie" não podia ser removido, desabilitado ou evitado pelo usuário. Modo incógnito? Inútil. Limpar cookies? Inútil. O rastreador era injetado no nível de rede, depois que o tráfego saía do dispositivo. A FCC multou a Verizon em US$ 1,35 milhão em 2016, o que equivale a troco de bala para uma empresa daquele porte.</p>
<p>A Comcast também foi flagrada injetando anúncios JavaScript nos navegadores de dispositivos conectados aos seus 3,5 milhões de hotspots WiFi.</p>
<h3>Reino Unido: Investigatory Powers Act</h3>
<p>Desde 2016, o "Snooper's Charter" obriga ISPs britânicos a armazenar o histórico de conexão de todos os clientes por 12 meses, acessível sem mandado judicial. O governo pode ver quais sites você acessou, quando, de qual dispositivo. Membros do parlamento são explicitamente protegidos dessa vigilância. Uma regra para eles, outra para o resto.</p>
<h3>Turquia: ISPs como braço do Estado</h3>
<p>Na Turquia, ISPs são obrigados a reter logs de 1 a 2 anos e, não oficialmente, a implementar Deep Packet Inspection (DPI). Quando o Twitter foi banido em 2014, os ISPs primeiro envenenaram o DNS, depois bloquearam todos os IPs do Twitter. Os turcos responderam pichando os endereços do DNS do Google (<code>8.8.8.8</code> e <code>8.8.4.4</code>) em muros pela cidade. O uso do Twitter no país cresceu 138%.</p>
<h2>O Estado como ameaça: vigilância, mandados secretos e perseguição política</h2>
<p>Se os casos acima mostram provedores falhando por incompetência, negligência ou ganância, este ponto é sobre algo pior: governos usando provedores como instrumento de vigilância em massa, com mandados secretos, sem contraditório e sem que o alvo sequer saiba que está sendo monitorado.</p>
<h3>EUA: a FISA Court e os 3,4 milhões de buscas sem mandado</h3>
<p>Nos Estados Unidos, a Section 702 do Foreign Intelligence Surveillance Act (FISA) permite que a NSA, o FBI e a CIA coletem comunicações de estrangeiros fora do país sem mandado judicial individualizado. Até aqui, parece razoável. O problema é o que acontece com os americanos (e qualquer pessoa que se comunique com esses alvos estrangeiros): suas mensagens, emails, ligações e textos são coletados "incidentalmente" e armazenados em bancos de dados que o FBI pode consultar livremente.</p>
<p>Só em 2021, o FBI realizou 3,4 milhões de buscas nessas bases sem qualquer mandado. Entre os alvos: manifestantes do Black Lives Matter (141 pessoas monitoradas por protestar contra o assassinato de George Floyd), mais de 19.000 doadores de uma campanha eleitoral, jornalistas, membros do Congresso, assessores parlamentares e, num caso particularmente absurdo, um juiz estadual que havia procurado o FBI para denunciar violações de direitos civis por um chefe de polícia local. O FBI pesquisou as comunicações dele. Do denunciante.</p>
<p>Essas buscas acontecem num tribunal secreto (a FISA Court) que funciona sem a presença do investigado, sem advogado de defesa e com taxa de aprovação que beira 99%. Em 2022, dos 354 pedidos de vigilância, apenas 7 foram rejeitados. O investigado nunca sabe que foi alvo. Nunca tem chance de se defender. E as empresas que recebem essas ordens são obrigadas por lei a cumpri-las e proibidas (sob gag order) de revelar que as receberam.</p>
<p>As National Security Letters (NSLs) são ainda piores: o FBI pode solicitar dados de provedores sem passar por juiz algum. Basta um agente atestar que a informação é "relevante para segurança nacional". A empresa é proibida de informar o usuário. É um sistema onde o Estado pode vasculhar a vida digital de qualquer cidadão sem acusação formal, sem julgamento e sem chance de defesa.</p>
<h3>Brasil: interceptação massiva e o uso político da vigilância</h3>
<p>No Brasil, a Lei 9.296/96 regulamenta a interceptação telemática, exigindo ordem judicial. Na teoria. Na prática, o volume de interceptações no Brasil é assustador. Em 2013, foram registrados mais de 50.000 avisos de interceptação enviados às operadoras de telecomunicações. Comparando: os EUA, com 120 milhões de habitantes a mais, autorizaram 3.576 no mesmo ano.</p>
<p>Em 2012, a Polícia Federal implementou o SIS (Sistema de Interceptação de Sinais), que permite interceptar qualquer comunicação na rede de uma operadora sem interação caso a caso com a telco. O sistema eliminou a necessidade de pedir cooperação técnica da operadora para cada alvo. Ou seja: a infraestrutura para vigilância em massa já está montada. Depende apenas de quem está no comando.</p>
<p>Em 2013, documentos revelaram que o Gabinete de Segurança Institucional da Presidência ordenou à ABIN monitorar sindicatos e movimentos sociais opositores. Líderes da ONG Xingu Vivo, que lutavam contra a construção da Usina de Belo Monte em terra indígena, foram espionados por agentes infiltrados. No estado de São Paulo, foi revelado o monitoramento de movimentos de moradia.</p>
<p>A LGPD (Lei Geral de Proteção de Dados) exclui explicitamente de seu escopo o tratamento de dados para fins de segurança do Estado, persecução penal e defesa nacional. Essa exceção existe para ser regulamentada por legislação específica que, até hoje, não foi criada. Resultado: há um buraco negro legal onde o Estado pode operar com pouquíssima supervisão quando o assunto é vigilância.</p>
<h3>O problema estrutural: seu ISP é o ponto de coleta</h3>
<p>Independente do país, o padrão se repete: o governo não precisa hackear seu dispositivo. Ele vai ao provedor, que por força de lei é obrigado a reter dados e, em muitos casos, entregar informações sem que o alvo seja notificado, sem direito a defesa e, frequentemente, sem que o próprio provedor questione a ordem.</p>
<p>No Reino Unido, o Investigatory Powers Act obriga a retenção por 12 meses. Na Turquia, de 1 a 2 anos. No Brasil, o Marco Civil da Internet exige guarda de registros de conexão por 1 ano e de registros de acesso a aplicações por 6 meses.</p>
<p>Você não precisa ser criminoso, suspeito ou investigado. Basta ser inconveniente. Jornalista investigando corrupção. Ativista ambiental. Advogado de direitos humanos. Doador de campanha. Ou simplesmente alguém que denunciou um policial corrupto, como o juiz americano espionado pelo FBI por fazer a coisa certa.</p>
<p>Quando seu tráfego passa em texto plano pelo provedor, quando seu DNS não é criptografado, quando você não usa VPN, cada pacote é evidência potencial num processo que pode nunca chegar ao seu conhecimento. A infraestrutura de vigilância já existe. A questão não é se ela será usada contra inocentes. A história mostra que já foi, é, e continuará sendo.</p>
<p>Proteger seu tráfego não é paranoia. É o mínimo de higiene digital para quem entende como funciona a cadeia de custódia entre o seu dispositivo e a internet.</p>
<h2>O que fazer: retome o controle</h2>
<h3>1. Use seu próprio DNS</h3>
<p>Pare de usar o DNS do provedor. Configure um provedor de DNS que respeite privacidade e ofereça filtragem:</p>
<table>
<thead>
<tr>
<th>Provedor</th>
<th>DoH</th>
<th>DoT</th>
<th>Bloqueio de Ads/Trackers</th>
<th>Preço</th>
</tr>
</thead>
<tbody><tr>
<td>NextDNS</td>
<td>Sim</td>
<td>Sim</td>
<td>Sim, configurável</td>
<td>Free / $19.90/ano</td>
</tr>
<tr>
<td>ControlD</td>
<td>Sim</td>
<td>Sim</td>
<td>Sim, configurável</td>
<td>Free / a partir de $2/mês</td>
</tr>
<tr>
<td>AdGuard DNS</td>
<td>Sim</td>
<td>Sim</td>
<td>Sim</td>
<td>Free / $2.49/mês</td>
</tr>
<tr>
<td>Quad9</td>
<td>Sim</td>
<td>Sim</td>
<td>Malware blocking</td>
<td>Gratuito</td>
</tr>
<tr>
<td>Cloudflare (1.1.1.1)</td>
<td>Sim</td>
<td>Sim</td>
<td>Apenas na versão families</td>
<td>Gratuito</td>
</tr>
</tbody></table>
<p>NextDNS e ControlD se destacam pela granularidade: você escolhe quais categorias bloquear, visualiza logs em tempo real e configura perfis por dispositivo. É basicamente um Pi-hole na nuvem, sem precisar manter hardware.</p>
<h3>2. DNS over TLS (DoT) e DNS over HTTPS (DoH)</h3>
<p>Não basta trocar o IP do DNS. Se a consulta continuar em texto plano, o provedor ainda pode interceptar, redirecionar ou até bloquear. Por isso é fundamental usar DNS criptografado:</p>
<p><strong>DoT (porta 853):</strong> Encapsula as consultas DNS em TLS. A maioria dos roteadores e sistemas operacionais modernos suporta nativamente. No Android, é o "DNS Privado" nas configurações de rede.</p>
<p><strong>DoH (porta 443):</strong> Encapsula as consultas DNS dentro de HTTPS. Mais difícil de bloquear pelo provedor, porque se mistura com tráfego web normal.</p>
<p>No Linux, configure com <code>systemd-resolved</code>:</p>
<pre><code class="language-ini"># /etc/systemd/resolved.conf
[Resolve]
DNS=45.90.28.0#SEUPROFILE.dns.nextdns.io
DNSOverTLS=yes
DNSSEC=yes
</code></pre>
<p><strong>Ou use o</strong> <code>dnscrypt-proxy</code> <strong>para DoH com ODoH (Oblivious DoH), que adiciona mais uma camada separando quem faz a consulta de quem resolve.</strong></p>
<p><a class="embed-card" href="https://esli.blog.br/dnscrypt-dns-stamps-e-dns-criptografado-o-guia-que-faltava">https://esli.blog.br/dnscrypt-dns-stamps-e-dns-criptografado-o-guia-que-faltava</a></p>

<h3>3. No celular: RethinkDNS e InviZible Pro</h3>
<p><strong>RethinkDNS</strong> (Android): Funciona como firewall + DNS resolver. Permite configurar DoH/DoT com NextDNS, ControlD ou qualquer endpoint customizado. Bloqueia conexões por app, mostra logs em tempo real e não precisa de root. É open-source.</p>
<p><strong>InviZible Pro</strong> (Android): Combina DNSCrypt + Tor + I2P + firewall. Permite rotear DNS via DNSCrypt ou Tor, enquanto o tráfego normal segue por VPN ou direto. Também open-source, disponível no F-Droid.</p>
<p>Se o seu Android suporta "DNS Privado" (Android 9+), configure diretamente com o hostname DoT do NextDNS, ControlD ou AdGuard. Mas o RethinkDNS oferece muito mais controle.</p>
<h3>4. Tenha seu próprio roteador em modo bridge</h3>
<p>O roteador que o provedor te entrega é território dele. Firmware proprietário, configurações limitadas, atualizações que ele faz (ou não faz) quando quer, e potencialmente com backdoors. A solução:</p>
<ol>
<li><p>Mude o equipamento do seu provedor para <strong>modo bridge</strong> (bridge mode). Isso faz com que ele funcione apenas como modem, delegando toda a parte de roteamento e firewall para o seu equipamento.</p>
</li>
<li><p>Conecte o seu roteador na porta WAN do modem em bridge.</p>
</li>
<li><p>Configure no seu roteador: DNS criptografado (DoT/DoH), firewall, VPN no nível de rede e WiFi com suas próprias regras.</p>
</li>
</ol>
<p>Se o provedor não aceitar bridge, configure o equipamento dele com DMZ apontando para o IP do seu roteador. Não é o ideal, mas remove boa parte do controle.</p>
<p>Roteadores recomendados para quem quer controle total: qualquer hardware que suporte <strong>OpenWrt</strong>, <strong>DDWRT</strong>, <strong>pfSense</strong> ou <strong>OPNsense</strong>. Se for algo mais acessível (ou portátil), um GL.iNet com OpenWrt pré-instalado já resolve muito.</p>
<h3>5. VPN: sempre</h3>
<p>Uma VPN criptografa todo o tráfego entre seu dispositivo e o servidor da VPN. Para o provedor, tudo que ele vê é uma conexão criptografada para um IP. Ele não sabe qual site você acessa, o que você baixa, nada.</p>
<p>O privacyguides.org recomenda três provedores: <strong>Mullvad</strong>, <strong>IVPN</strong> e <strong>ProtonVPN</strong>. Não vou repetir aqui o que já escrevi em <a href="https://esli.blog.br/qual-melhor-vpn">https://esli.blog.br/qual-melhor-vpn</a> mas o resumo é: se a VPN pede seu email para cadastro, já começou errado.</p>
<p><strong>TorVPN / Tor:</strong> Para anonimato real, o Tor continua sendo a referência. Não é rápido, não é prático para tudo, mas quando você precisa que ninguém saiba o que você está fazendo (nem o provedor de VPN), é o caminho.</p>
<p><strong>VPN no roteador:</strong> Configure a VPN diretamente no seu roteador (OpenWrt, pfSense, OPNsense ou GL.iNet suportam nativamente). Com isso, todos os dispositivos da rede passam pela VPN automaticamente. Smart TV, Alexa, dispositivos IoT... tudo protegido sem precisar de configuração individual.</p>
<pre><code class="language-bash"># Exemplo: WireGuard no OpenWrt via CLI
opkg update &amp;&amp; opkg install wireguard-tools luci-proto-wireguard
# Configure a interface e importe o .conf do seu provedor VPN
</code></pre>
<h3>6. Navegador: configure os bloqueadores</h3>
<p>Navegadores como Brave, Tor Browser e Mullvad Browser vêm com proteções de privacidade ativadas por padrão. Mas é possível ir além:</p>
<p><strong>No Brave:</strong></p>
<ul>
<li><p>Shields no modo agressivo</p>
</li>
<li><p>Filtros personalizados em <code>brave://settings/shields/filters</code></p>
</li>
<li><p>Scriptlets customizados (modo desenvolvedor) para remover elementos indesejados</p>
</li>
<li><p>DNS privado configurado nas settings do browser</p>
</li>
</ul>
<p>Já escrevi sobre isso: <a href="https://esli.blog.br/funcoes-avancadas-no-brave-browser">https://esli.blog.br/funcoes-avancadas-no-brave-browser</a> e mantenho meus filtros aqui: <a href="https://github.com/Esl1h/Brave-Filters-and-Scriptlets">https://github.com/Esl1h/Brave-Filters-and-Scriptlets</a></p>
<p><strong>No Tor Browser:</strong> Use como está. Não instale extensões, não altere o user agent, não maximize a janela. O Tor funciona melhor quanto menos você mexe nele.</p>
<p><strong>No Mullvad Browser:</strong> Fork do Firefox mantido pela Mullvad e pelo Tor Project. Focado em anti-fingerprinting. Se você não quer usar o Tor, mas quer o máximo de privacidade sem ser Brave, essa é a opção.</p>
<p>Acompanhe os resultados de privacidade dos navegadores em <a href="https://privacytests.org/">https://privacytests.org/</a></p>
<h3>7. Outras medidas</h3>
<p><strong>DNSSEC:</strong> Valida que a resposta DNS veio de um servidor legítimo. Protege contra envenenamento de cache. Ative no seu resolver.</p>
<p><strong>ECH (Encrypted Client Hello):</strong> A evolução do ESNI. Criptografa o SNI no TLS handshake, impedindo que o provedor saiba qual domínio você está acessando mesmo em conexões HTTPS. O Brave e Firefox já suportam.</p>
<p><strong>OONI Probe:</strong> Ferramenta open-source que testa se o seu provedor está censurando, bloqueando ou manipulando o tráfego. Rode periodicamente.</p>
<p><strong>DNS Leak Test:</strong> Acesse <a href="https://dnsleaktest.com">https://dnsleaktest.com</a> ou <a href="https://www.whatsmydns.net">https://www.whatsmydns.net</a> para verificar se seu DNS configurado é realmente o que está sendo usado. Se aparecer o DNS do provedor, algo está errado.</p>
<p><strong>Blokada / NetGuard (Android):</strong> Se não quiser usar RethinkDNS, são alternativas para firewall e bloqueio de trackers no celular sem root.</p>
<p><strong>Pi-hole / AdGuard Home (Self-hosted):</strong> Se preferir manter o controle total do DNS dentro da sua rede, sem depender de serviços externos, instale um Pi-hole ou AdGuard Home no seu servidor local (um Raspberry Pi resolve). Configure como DNS upstream o NextDNS ou Quad9 com DoT.</p>
<h2>Resumo: a pilha de proteção</h2>
<p>Do mais básico ao mais avançado, em ordem de implementação:</p>
<ol>
<li><p><strong>Troque o DNS</strong> para NextDNS, ControlD ou Quad9</p>
</li>
<li><p><strong>Ative DoT/DoH</strong> em todos os dispositivos</p>
</li>
<li><p><strong>Instale RethinkDNS ou InviZible</strong> no celular</p>
</li>
<li><p><strong>Use Brave, Tor ou Mullvad Browser</strong> com bloqueadores configurados</p>
</li>
<li><p><strong>Compre seu próprio roteador</strong> e peça bridge no do provedor</p>
</li>
<li><p><strong>Configure VPN</strong> no roteador e nos dispositivos</p>
</li>
<li><p><strong>Ative ECH</strong> no navegador</p>
</li>
<li><p><strong>Rode OONI Probe e DNS Leak Test</strong> periodicamente</p>
</li>
<li><p><strong>Self-host</strong> DNS com Pi-hole ou AdGuard Home se quiser ir além</p>
</li>
</ol>
<p>Nenhuma dessas medidas isoladamente resolve o problema. Mas combinadas, elas transformam a visão que o provedor tem de você: de um livro aberto para uma caixa preta.</p>
<h2>Além da rede: criptografia, autenticação e dados em repouso</h2>
<p>Este artigo foca na proteção do tráfego contra o provedor, mas não existe segurança de rede sem segurança local. De nada adianta criptografar o DNS e usar VPN se seus dados estão em plaintext no disco, seu backup na nuvem não tem criptografia client-side e seu login depende apenas de uma senha que você reusa em 15 serviços.</p>
<p>Resumidamente (porque cada um desses tópicos merece artigo próprio, e já escrevi sobre vários deles):</p>
<p><strong>Disco criptografado:</strong> LUKS no Linux, FileVault no macOS, BitLocker no Windows. Se o dispositivo for roubado, perdido ou apreendido, os dados ficam inacessíveis sem a chave. No Linux, encripte o disco na instalação e monte <code>/var/log</code>, <code>/var/tmp</code> e <code>/tmp</code> como tmpfs para não deixar rastros em disco. Swap também deve ser criptografada.</p>
<p><strong>Backups e nuvem:</strong> Nunca suba arquivos para cloud storage sem criptografia client-side. O provedor de nuvem (Google, Dropbox, OneDrive) tem acesso ao conteúdo, assim como qualquer governo que solicite via mandado. Use Cryptomator para nuvem (criptografia por arquivo, transparente, funciona com qualquer provedor) ou Picocrypt para arquivos avulsos. Para containers maiores ou hidden volumes, VeraCrypt. Para quem respira terminal, Tomb (wrapper LUKS com key file separado e steganografia opcional).</p>
<p><strong>2FA/MFA e chave física:</strong> Habilite autenticação de dois fatores em tudo. SMS não é 2FA seguro (SIM swap existe). Use TOTP via Aegis (Android, open-source) ou diretamente via Yubikey com o Yubico Authenticator. A Yubikey é uma chave física que suporta FIDO2, U2F, OpenPGP, PIV e TOTP. Funciona para login no sistema (via PAM no Linux), SSH (ed25519-sk), GPG e praticamente qualquer serviço que suporte WebAuthn. Se você não tem uma, considere seriamente comprar. Se tem, configure ela em tudo.</p>
<p><strong>Gerenciador de senhas:</strong> Senhas únicas, complexas e armazenadas em um gerenciador com criptografia E2EE. ProtonPass, Bitwarden ou KeePassXC. Nunca reutilize senhas entre serviços.</p>
<p>Já escrevi em detalhes sobre tudo isso:</p>
<ul>
<li><p>Criptografia para iniciantes: <a href="https://esli.blog.br/criptografia-para-iniciantes">https://esli.blog.br/criptografia-para-iniciantes</a></p>
</li>
<li><p>Ferramentas de criptografia (VeraCrypt, Cryptomator, Picocrypt, Kryptor, Tomb): <a href="https://esli.blog.br/ferramentas-para-criptografia">https://esli.blog.br/ferramentas-para-criptografia</a></p>
</li>
<li><p>Como escolher a ferramenta certa: <a href="https://esli.blog.br/como-escolher-ferramentas-de-criptografia">https://esli.blog.br/como-escolher-ferramentas-de-criptografia</a></p>
</li>
<li><p>Certificados, OpenSSL, GPG e OpenPGP: <a href="https://esli.blog.br/certificados-e-openssl">https://esli.blog.br/certificados-e-openssl</a></p>
</li>
<li><p>Yubikey (série completa):</p>
<ul>
<li><p>Introdução ao 2FA: <a href="https://esli.blog.br/yubikey-introducao">https://esli.blog.br/yubikey-introducao</a></p>
</li>
<li><p>Instalação no Linux: <a href="https://esli.blog.br/yubikey-linux-instalacao">https://esli.blog.br/yubikey-linux-instalacao</a></p>
</li>
<li><p>2FA no console, sudo e SSH: <a href="https://esli.blog.br/yubikey-console-sudo-ssh">https://esli.blog.br/yubikey-console-sudo-ssh</a></p>
</li>
<li><p>SSH com ed25519-sk: <a href="https://esli.blog.br/yubikey-ssh-ed25519-ecdsa">https://esli.blog.br/yubikey-ssh-ed25519-ecdsa</a></p>
</li>
<li><p>Chaves GPG na Yubikey: <a href="https://esli.blog.br/yubikey-chaves-gpg">https://esli.blog.br/yubikey-chaves-gpg</a></p>
</li>
</ul>
</li>
<li><p>Privacidade e Segurança (guia completo): <a href="https://esli.blog.br/privacidade-e-seguranca-2025">https://esli.blog.br/privacidade-e-seguranca-2025</a></p>
</li>
</ul>
<p>A proteção de rede que este artigo descreve é uma camada. Criptografia de dados em repouso é outra. Autenticação forte é outra. Nenhuma substitui a outra. Todas se complementam.</p>
<h2>Conclusão</h2>
<p>A internet é um serviço pelo qual você paga. Mas o provedor não se comporta como um simples "teletransportador" de pacotes. Ele inspeciona, registra, vende, compartilha e, quando pressionado por governos, entrega sem questionar.</p>
<p>Confiar no provedor com seus dados é como confiar no carteiro para não ler suas cartas. Só que o carteiro tem um scanner, uma impressora e um contrato com empresas de marketing.</p>
<p>A boa notícia é que as ferramentas existem e estão acessíveis. A maioria é gratuita, open-source e documentada. O custo real é o tempo de configurar. E se você chegou até aqui, provavelmente já tem esse tempo.</p>
<p>Use-o.</p>
<p>Referências e leitura complementar:</p>
<ul>
<li><p><a href="https://privacyguides.org">https://privacyguides.org</a></p>
</li>
<li><p><a href="https://privacytests.org">https://privacytests.org</a></p>
</li>
<li><p><a href="https://ssd.eff.org">https://ssd.eff.org</a></p>
</li>
<li><p><a href="https://esli.blog.br/privacidade-e-seguranca-2025">https://esli.blog.br/privacidade-e-seguranca-2025</a></p>
</li>
<li><p><a href="https://esli.blog.br/qual-melhor-vpn">https://esli.blog.br/qual-melhor-vpn</a></p>
</li>
<li><p><a href="https://esli.blog.br/qual-melhor-navegador">https://esli.blog.br/qual-melhor-navegador</a></p>
</li>
<li><p><a href="https://esli.blog.br/criptografia-para-iniciantes">https://esli.blog.br/criptografia-para-iniciantes</a></p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/2e0780c9-33e0-4d43-82f4-d5f9e8b45963.png" alt="" style="display:block;margin:0 auto" />]]></content:encoded></item><item><title><![CDATA[How to get rid of ads everywhere]]></title><description><![CDATA[TL;DR: Brave Browser + Anti Paywall + NextDNS + VPN + SponsorBlock + SmartTubeNext

The amount of ads on the internet today isn't just annoying, it's a mental health hazard. Every click, every scroll,]]></description><link>https://esli.blog.br/how-to-get-rid-of-ads-everywhere</link><guid isPermaLink="true">https://esli.blog.br/how-to-get-rid-of-ads-everywhere</guid><category><![CDATA[ads]]></category><category><![CDATA[adblock]]></category><category><![CDATA[Brave]]></category><category><![CDATA[Brave Browser]]></category><category><![CDATA[vpn]]></category><category><![CDATA[youtube]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Sun, 29 Mar 2026 23:02:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5df318ae066598ab275294bf/30d1cf66-3ea7-48cb-b90c-d6b3a84938ce.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>TL;DR: Brave Browser + Anti Paywall + NextDNS + VPN + SponsorBlock + SmartTubeNext</p>
</blockquote>
<p>The amount of ads on the internet today isn't just annoying, it's a mental health hazard. Every click, every scroll, every video is an obstacle course of banners, pop-ups, autoplaying videos, and sponsored content fighting for your attention like desperate street vendors. Blocking ads isn't just a matter of convenience anymore, it's an act of self-defense. And more than that, it's a statement: this monetization model is broken, intrusive, and unsustainable. The more people block ads, the louder the message gets: the internet needs to find a better way to fund itself without turning every screen into a billboard. Here's how to take back control across all your devices.</p>
<h2>Brave Browser</h2>
<p>Desktop and Smartphone: switch to Brave.<br />If you don't care about tokens and other built-in features… just disable them. Turn off the VPN button, remove Brave Rewards, and anything else you don't like or that made you dismiss Brave in the past.</p>
<p>Chrome is unbearable - it killed extensions (Manifest V3) and keeps doubling down on tracking. Brave runs on Chromium (<strong>Chromium ≠ Google Chrome</strong>).</p>
<p>With Brave, you can go deeper into ad blocking through filter lists and Scriptlets. But out of the box, Brave Shield already strips away almost everything.</p>
<p>Here are some filters and scriptlets I use to remove specific items on certain sites: <a href="https://github.com/Esl1h/Brave-Filters-and-Scriptlets">https://github.com/Esl1h/Brave-Filters-and-Scriptlets</a></p>
<p>Check <a href="https://privacytests.org/">https://privacytests.org/</a> for privacy data on Brave, in case you still have doubts.</p>
<p>I'm currently keeping an eye on Orion Browser (Kagi) and Ladybird. My second choice is Mullvad Browser (a Firefox fork). But to match what Brave offers out of the box, you'd need to pile on extensions and spend a good while tweaking settings.</p>
<h3>Shields (Brave)</h3>
<table>
<thead>
<tr>
<th><strong>Internal URL</strong></th>
<th><strong>Purpose</strong></th>
</tr>
</thead>
<tbody><tr>
<td>brave://shields/</td>
<td>Global Brave Shields configuration hub, where you can set blocking policies for trackers, ads, and scripts.</td>
</tr>
<tr>
<td>brave://adblock/</td>
<td>Manages ad and tracker filter lists, allowing you to add, remove, or customize rules.</td>
</tr>
<tr>
<td>brave://privacy/</td>
<td>Dedicated privacy settings page, including permissions, cookies, tracking, and sensitive data controls.</td>
</tr>
</tbody></table>
<h2>Anti-paywall</h2>
<p>Here I go into more detail about anti-paywall: <a href="https://esli.blog.br/pulando-o-muro-do-paywall">https://esli.blog.br/pulando-o-muro-do-paywall</a></p>
<p><a href="https://burles.co">https://burles.co</a> is an extension that blocks the paywall script from running (create to work with Brazilian sites + Tampermonkey).</p>
<p>It can be installed or run via Tampermonkey (install the Tampermonkey extension, enable developer mode, then open the burlesco.js URL and click install).</p>
<p>Another way to block paywalls is through Brave: click on Shields, switch to advanced mode, and block scripts. However, this will block all scripts, not just the ones responsible for the paywall.</p>
<h2>NextDNS</h2>
<p>Use NextDNS as your DNS. Even if you already run a Pi-Hole in your home lab, add NextDNS on top of it.</p>
<p>The free tier is limited to 300,000 requests per month, more than enough for regular use. With 4 or 5 devices at home (router + laptops + phones), you'll hardly this queries per month especially with caching enabled. The paid plan costs around €20/year, not that expensive, really.</p>
<p>Link: <a href="https://nextdns.io/?from=yes2mwwr">https://nextdns.io/?from=yes2mwwr</a></p>
<p>The blocking options, lists, and settings are quite extensive.</p>
<p>And once again, just like Brave Browser, besides removing ads, it also improves your security.</p>
<p>Set up NextDNS on all your devices. Configure it as Private DNS in Brave's settings.</p>
<p>Add NextDNS as Private DNS in your smartphone's advanced settings.</p>
<p>Set it up on your router: this effectively enables ad blocking on devices like Alexa, Smart TVs, and others.</p>
<p>If your phone doesn't allow changing the DNS, consider a different brand next time. But as long as it's configured on the router, you'll still get the blocking benefits when connected to your local network/Wi-Fi.</p>
<h2>YouTube</h2>
<h3>VPN</h3>
<p>Some countries don't have YouTube monetization, meaning content creators don't earn ad revenue from views in those regions.</p>
<p>By connecting a VPN on your TV or other device to one of these non-monetized countries, you may see no ads at all. Of course, things can get messy — Google might still push ads regardless.</p>
<p>I usually connect through Turkmenistan and Albania — no YouTube ads. Though sometimes YouTube starts showing ads as if I were in France.</p>
<p>Here's a list of countries without monetization: <a href="https://isthischannelmonetized.com/data/youtube-monetized-countries/">https://isthischannelmonetized.com/data/youtube-monetized-countries/</a></p>
<p>That said, I've seen some content creators apply geoblocking on their videos.</p>
<p>Using a VPN can block YouTube ads on your smartphone, <strong>but the best approach is to use Brave Browser and ditch the app entirely</strong>.</p>
<h3>Blocking YouTube ads on Smart TVs</h3>
<p>My TV is also routed through NextDNS (at the router level), which already blocks Amazon ads on FireStick/FireTV as well as ads on Android TV and Google TV.</p>
<p>On Google TV (updated Android TV), I installed AdGuard, but didn't get the results I wanted. NextDNS on the network plus SmartTubeNext are the best combo to remove YouTube ads on TV and strip out the other ads that show up in the TV's OS or inside other apps.</p>
<h3>SmartTubeNext</h3>
<p>For FireTV, Android, and Google TV: <a href="https://smarttubenext.com/">https://smarttubenext.com/</a></p>
<p>Install SmartTubeNext. On FireStick, enable developer mode (go to My Fire TV, click the FireStick info several times). Download the Downloader app (there's no way to download it through the default Silk browser on FireStick), then open the SmartTubeNext website inside Downloader, download it, and install.</p>
<p><a href="https://smarttubenext.com/firestick/">https://smarttubenext.com/firestick/</a></p>
<p>It blocks all ads including sponsored segments within videos.</p>
<p>The player and display settings are highly customizable.</p>
<p>If you're not using an Amazon FireTV Stick, use this link for Android TV: <a href="https://smarttubenext.com/android-tv-box/">https://smarttubenext.com/android-tv-box/</a></p>
<h3>SponsorBlock</h3>
<p>The secret behind SmartTubeNext and other YouTube frontends — whether on Smart TVs or any other device — is SponsorBlock: <a href="https://sponsor.ajay.app/">https://sponsor.ajay.app/</a></p>
<p>It's available as a component across many apps that block YouTube ads on Android, Android TV, Google TV, as a Tampermonkey userscript, in players like MPV, Kodi, Chromecast, Roku, Apple TV, iOS, desktop systems (Windows, Linux, and macOS), and finally as a browser extension. Full list here: <a href="https://github.com/ajayyy/SponsorBlock/wiki/3rd-Party-Ports">https://github.com/ajayyy/SponsorBlock/wiki/3rd-Party-Ports</a></p>
<p>With SponsorBlock — on any app, any device, any operating system — it will automatically skip video segments containing sponsored content, intro animations, end cards and credits, subscribe/like/comment prompts, paid promotions, and in-video ads.</p>
]]></content:encoded></item><item><title><![CDATA[sysup: um comando para atualizar todas as suas máquinas em qualquer distro]]></title><description><![CDATA[Quem mantém mais de uma distribuição Linux sabe a dor: dnf update aqui, pacman -Syu ali, apt upgrade acolá. Multiplica isso por cinco máquinas — dois laptops com Omarchy e EndeavourOS (Arch), outro com Ubuntu 25.04, um desktop com Fedora 43 e um home...]]></description><link>https://esli.blog.br/sysup-um-comando-para-atualizar-todas-as-suas-maquinas-em-qualquer-distro</link><guid isPermaLink="true">https://esli.blog.br/sysup-um-comando-para-atualizar-todas-as-suas-maquinas-em-qualquer-distro</guid><category><![CDATA[zsh]]></category><category><![CDATA[functions]]></category><category><![CDATA[Bash]]></category><category><![CDATA[bash script]]></category><category><![CDATA[oh-my-zsh]]></category><category><![CDATA[System administration]]></category><category><![CDATA[Script]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Mon, 09 Feb 2026 16:24:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/WItUgoQSJp0/upload/7457c066975f8235cc5c9b09e6f4a775.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Quem mantém mais de uma distribuição Linux sabe a dor: <code>dnf update</code> aqui, <code>pacman -Syu</code> ali, <code>apt upgrade</code> acolá. Multiplica isso por cinco máquinas — dois laptops com Omarchy e EndeavourOS (Arch), outro com Ubuntu 25.04, um desktop com Fedora 43 e um home server com Debian (sem contar os Raspberries, porque esses a gente finge que não precisa atualizar) — e a tarefa de “rodar um update” vira um exercício de memória muscular para dedos que já não são tão jovens.</p>
<p>A solução? Uma <strong>zsh function</strong> que detecta o package manager e faz tudo com um único comando: <code>sysup</code>.</p>
<p>Mas antes de chegar nela, vale entender como o Zsh organiza esse tipo de extensão.</p>
<h2 id="heading-a-estrutura-zsh">A estrutura <code>~/.zsh/</code></h2>
<p>O Zsh permite organizar customizações em diretórios dedicados. Uma convenção comum (e que uso nos meus <a target="_blank" href="https://github.com/Esl1h/dotfiles">dotfil</a><a target="_blank" href="https://github.com/Esl1h/dotfiles">es):</a></p>
<pre><code class="lang-bash">~/.zsh/
├── <span class="hljs-built_in">functions</span>/     <span class="hljs-comment"># Funções carregadas sob demanda (autoload)</span>
├── completions/   <span class="hljs-comment"># Scripts de completion customizados (_comando)</span>
</code></pre>
<h3 id="heading-functions"><code>functions/</code></h3>
<p>Cada arquivo é <strong>uma função</strong>. O nome do arquivo = nome da função. Sem extensão, sem shebang. O Zsh carrega o conteúdo do arquivo como corpo da função quando ela é chamada pela primeira vez — isso é o <strong>autoload</strong>.</p>
<h3 id="heading-completions"><code>completions/</code></h3>
<p>Segue a mesma lógica, mas para funções de completion (<code>_nome</code>). Se você escreve um CLI próprio e quer tab-completion, é aqui que o script de completion fica.</p>
<h2 id="heading-as-4-linhas-no-zshrc">As 4 linhas no <code>~/.zshrc</code></h2>
<pre><code class="lang-bash">fpath=(~/.zsh/<span class="hljs-built_in">functions</span> <span class="hljs-variable">$fpath</span>)
<span class="hljs-built_in">autoload</span> -Uz ~/.zsh/<span class="hljs-built_in">functions</span>/*(N:t)
<span class="hljs-built_in">autoload</span> -Uz compinit &amp;&amp; compinit
<span class="hljs-built_in">autoload</span> -Uz promptinit &amp;&amp; promptinit
</code></pre>
<h3 id="heading-linha-1-fpathzshfunctions-fpath">Linha 1: <code>fpath=(~/.zsh/functions $fpath)</code></h3>
<p>Adiciona <code>~/.zsh/functions/</code> ao <strong>fpath</strong> (function path) — o equivalente do <code>$PATH</code>, mas para funções do Zsh. O Zsh só encontra funções via autoload se elas estiverem em algum diretório listado no <code>$fpath</code>. Ao prepend (<code>~/.zsh/functions</code> antes de <code>$fpath</code>), suas funções têm prioridade sobre as do sistema.</p>
<p>Se tiver um diretório <code>completions/</code>, adicionaria da mesma forma:</p>
<pre><code class="lang-bash">fpath=(~/.zsh/completions ~/.zsh/<span class="hljs-built_in">functions</span> <span class="hljs-variable">$fpath</span>)
</code></pre>
<h3 id="heading-linha-2-autoload-uz-zshfunctionsnt">Linha 2: <code>autoload -Uz ~/.zsh/functions/*(N:t)</code></h3>
<p>Registra <strong>todas</strong> as funções do diretório para autoload.</p>
<p>Dissecando:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Componente</td><td>Função</td></tr>
</thead>
<tbody>
<tr>
<td><code>autoload</code></td><td>Marca uma função para carregamento sob demanda (lazy load)</td></tr>
<tr>
<td><code>-U</code></td><td>Suprime alias expansion — evita conflitos</td></tr>
<tr>
<td><code>-z</code></td><td>Força estilo Zsh (vs. Ksh)</td></tr>
<tr>
<td><code>*(N:t)</code></td><td>Glob com qualificadores: <code>N</code> = nullglob (não dá erro se vazio), <code>:t</code> = tail (extrai só o nome do arquivo, sem o path)</td></tr>
</tbody>
</table>
</div><p>O <code>:t</code> é essencial. Sem ele, o autoload receberia <code>/home/user/.zsh/functions/sysup</code> em vez de apenas <code>sysup</code>.</p>
<p>A função <strong>não é carregada em memória nesse momento</strong>. O Zsh apenas registra que, quando <code>sysup</code> for chamado, deve buscar e carregar o arquivo correspondente. Lazy loading puro.</p>
<h3 id="heading-linha-3-autoload-uz-compinit-ampamp-compinit">Linha 3: <code>autoload -Uz compinit &amp;&amp; compinit</code></h3>
<p>Carrega e inicializa o sistema de completion do Zsh. O <code>compinit</code> escaneia o <code>$fpath</code> procurando arquivos <code>_*</code> (prefixo underscore) e os registra como funções de completion. Sem isso, nenhum tab-completion customizado funciona.</p>
<h3 id="heading-linha-4-autoload-uz-promptinit-ampamp-promptinit">Linha 4: <code>autoload -Uz promptinit &amp;&amp; promptinit</code></h3>
<p>Carrega o sistema de temas de prompt. Permite usar <code>prompt -l</code> para listar temas disponíveis e <code>prompt &lt;tema&gt;</code> para aplicar. Útil se você usa temas de prompt distribuídos via <code>$fpath</code>, embora quem usa Starship ou p10k (meu caso) talvez nunca toque nisso.</p>
<h1 id="heading-o-sysup">O Sysup</h1>
<p>Código completo: <a target="_blank" href="https://github.com/Esl1h/dotfiles/blob/main/.zsh/functions/sysup">dotfiles</a><a target="_blank" href="https://github.com/Esl1h/dotfiles/blob/main/.zsh/functions/sysup">/.zsh/fu</a><a target="_blank" href="https://github.com/Esl1h/dotfiles/blob/main/.zsh/functions/sysup">nctions/sysup</a></p>
<pre><code class="lang-bash"><span class="hljs-comment"># Description: Dynamic package manager detection and global system update</span>
<span class="hljs-comment"># Usage: sysup</span>

<span class="hljs-function"><span class="hljs-title">_sysup_log</span></span>() {
  <span class="hljs-built_in">print</span> -P <span class="hljs-string">"%F{blue}==&gt;%f %B<span class="hljs-variable">$1</span>%b"</span>
}

<span class="hljs-comment"># 1. Universal Package Managers (Sandboxed)</span>
<span class="hljs-keyword">if</span> <span class="hljs-built_in">command</span> -v flatpak &amp;&gt;/dev/null; <span class="hljs-keyword">then</span>
  _sysup_log <span class="hljs-string">"Updating Flatpaks..."</span>
  flatpak update -y
<span class="hljs-keyword">fi</span>

<span class="hljs-keyword">if</span> <span class="hljs-built_in">command</span> -v snap &amp;&gt;/dev/null; <span class="hljs-keyword">then</span>
  _sysup_log <span class="hljs-string">"Refreshing Snaps..."</span>
  sudo snap refresh
<span class="hljs-keyword">fi</span>

<span class="hljs-comment"># 2. Native System Package Managers</span>
<span class="hljs-keyword">if</span> <span class="hljs-built_in">command</span> -v dnf &amp;&gt;/dev/null; <span class="hljs-keyword">then</span>
  _sysup_log <span class="hljs-string">"Running DNF Update..."</span>
  sudo dnf update -y
<span class="hljs-keyword">elif</span> <span class="hljs-built_in">command</span> -v yay &amp;&gt;/dev/null; <span class="hljs-keyword">then</span>
  _sysup_log <span class="hljs-string">"Running Yay (AUR/Pacman)..."</span>
  yay -Syu --noconfirm
<span class="hljs-keyword">elif</span> <span class="hljs-built_in">command</span> -v pacman &amp;&gt;/dev/null; <span class="hljs-keyword">then</span>
  _sysup_log <span class="hljs-string">"Running Pacman..."</span>
  sudo pacman -Syu --noconfirm
<span class="hljs-keyword">elif</span> <span class="hljs-built_in">command</span> -v apt &amp;&gt;/dev/null; <span class="hljs-keyword">then</span>
  _sysup_log <span class="hljs-string">"Running APT..."</span>
  sudo apt update &amp;&amp; sudo apt upgrade -y
<span class="hljs-keyword">elif</span> <span class="hljs-built_in">command</span> -v yum &amp;&gt;/dev/null; <span class="hljs-keyword">then</span>
  _sysup_log <span class="hljs-string">"Running YUM..."</span>
  sudo yum update -y
<span class="hljs-keyword">elif</span> <span class="hljs-built_in">command</span> -v zypper &amp;&gt;/dev/null; <span class="hljs-keyword">then</span>
  _sysup_log <span class="hljs-string">"Running Zypper..."</span>
  sudo zypper patch
<span class="hljs-keyword">fi</span>

_sysup_log <span class="hljs-string">"System update completed."</span>
</code></pre>
<h3 id="heading-logica">Lógica</h3>
<p>O script faz detecção dinâmica de package manager via <code>command -v</code> e executa o update apropriado.</p>
<p>Divide em duas categorias:</p>
<p><strong>1. Package managers universais (sandboxed)</strong> — sempre executados se presentes:</p>
<pre><code class="lang-bash"><span class="hljs-keyword">if</span> <span class="hljs-built_in">command</span> -v flatpak &amp;&gt;/dev/null; <span class="hljs-keyword">then</span>
  _sysup_log <span class="hljs-string">"Updating Flatpaks..."</span>
  flatpak update -y
<span class="hljs-keyword">fi</span>
<span class="hljs-keyword">if</span> <span class="hljs-built_in">command</span> -v snap &amp;&gt;/dev/null; <span class="hljs-keyword">then</span>
  _sysup_log <span class="hljs-string">"Refreshing Snaps..."</span>
  sudo snap refresh
<span class="hljs-keyword">fi</span>
</code></pre>
<p>Flatpak e Snap coexistem com o gerenciador nativo, então ambos rodam independentemente (blocos <code>if</code> paralelos, não <code>elif</code>).</p>
<p><strong>2. Package manager nativo</strong> — mutuamente exclusivo:</p>
<pre><code class="lang-bash"><span class="hljs-keyword">if</span> <span class="hljs-built_in">command</span> -v dnf &amp;&gt;/dev/null; <span class="hljs-keyword">then</span>
  sudo dnf update -y
<span class="hljs-keyword">elif</span> <span class="hljs-built_in">command</span> -v yay &amp;&gt;/dev/null; <span class="hljs-keyword">then</span>
  yay -Syu --noconfirm
<span class="hljs-keyword">elif</span> <span class="hljs-built_in">command</span> -v pacman &amp;&gt;/dev/null; <span class="hljs-keyword">then</span>
  sudo pacman -Syu --noconfirm
<span class="hljs-keyword">elif</span> <span class="hljs-built_in">command</span> -v apt &amp;&gt;/dev/null; <span class="hljs-keyword">then</span>
  sudo apt update &amp;&amp; sudo apt upgrade -y
<span class="hljs-keyword">elif</span> <span class="hljs-built_in">command</span> -v yum &amp;&gt;/dev/null; <span class="hljs-keyword">then</span>
  sudo yum update -y
<span class="hljs-keyword">elif</span> <span class="hljs-built_in">command</span> -v zypper &amp;&gt;/dev/null; <span class="hljs-keyword">then</span>
  sudo zypper patch
<span class="hljs-keyword">fi</span>
</code></pre>
<p>A cadeia <code>elif</code> garante que <strong>apenas um</strong> gerenciador nativo execute. A ordem importa:</p>
<ul>
<li><p><code>yay</code> antes de <code>pacman</code>: se yay está instalado, é preferível porque já cobre AUR + repositórios oficiais</p>
</li>
<li><p><code>dnf</code> antes de <code>yum</code>: em distros modernas baseadas em Red Hat, dnf é o padrão</p>
</li>
<li><p><code>apt</code> cobre Debian/Ubuntu</p>
</li>
</ul>
<h3 id="heading-deteccao-com-command-v">Detecção com <code>command -v</code></h3>
<p>O <code>command -v</code> é preferível a <code>which</code> porque:</p>
<ul>
<li><p>É um builtin do shell (não depende de binário externo)</p>
</li>
<li><p>Retorna 0/1 de forma confiável</p>
</li>
<li><p><code>which</code> tem comportamentos inconsistentes entre distros</p>
</li>
</ul>
<p>O redirecionamento <code>&amp;&gt;/dev/null</code> suprime stdout e stderr — queremos apenas o exit code.</p>
<h2 id="heading-usando">Usando…</h2>
<p>Só chamar o <code>sysup</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770653861043/43f4bac7-faac-4600-8a65-a66d5dda46de.png" alt class="image--center mx-auto" /></p>
<p>Só… Simples, rápido, fácil… sem reinventar a roda, sem precisar de milhares de validações, variáveis e etc. Pois conheço meu ambiente.</p>
<p>Uma função, qualquer máquina. Os mesmos dotfiles sincronizados via Git em todas as máquinas, e cada uma executa o caminho correto automaticamente.</p>
<p>O código está disponível no repositório dotfiles — com o resto da minha configuração de Zsh.</p>
]]></content:encoded></item><item><title><![CDATA[Não caia no hype anti-AI]]></title><description><![CDATA[Fatos são fatos: a IA mudou a programação para sempre. Não importa se você adora escrever código linha por linha, se defende o minimalismo no software ou se torce para que o modelo econômico atual das big techs de IA imploda — nada disso altera a rea...]]></description><link>https://esli.blog.br/nao-caia-no-hype-anti-ai</link><guid isPermaLink="true">https://esli.blog.br/nao-caia-no-hype-anti-ai</guid><category><![CDATA[AI]]></category><category><![CDATA[IA]]></category><category><![CDATA[vibe coding]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Programming Tips]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Mon, 09 Feb 2026 14:53:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/kGZ76pKsB8A/upload/34a8bf581bee5af6a14652e35635cb92.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Fatos são fatos: a IA mudou a programação para sempre. Não importa se você adora escrever código linha por linha, se defende o minimalismo no software ou se torce para que o modelo econômico atual das big techs de IA imploda — nada disso altera a realidade do que está acontecendo.</p>
<p>LLMs de última geração já conseguem concluir grandes subtarefas ou projetos de médio porte sozinhos, com pouca assistência humana, caso recebam um conjunto razoável de orientações sobre o resultado esperado. O grau de sucesso varia conforme o tipo de problema — quanto mais isolado e representável textualmente, melhor (programação de sistemas é particularmente adequada) — e depende da capacidade do programador de criar uma representação mental clara do problema para comunicá-la ao modelo.</p>
<p>Mas, em termos gerais, escrever código manualmente para a maioria dos projetos já não faz sentido prático, a não ser por diversão.</p>
<h2 id="heading-a-economia-e-irrelevante-para-a-tendencia">A economia é irrelevante para a tendência</h2>
<p>Não importa se as empresas de IA não conseguirão recuperar seus investimentos e o mercado de ações entrar em colapso. Não importa se algum CEO de unicórnio está dizendo algo desanimador ou absurdo. A tecnologia já escapou da garrafa. A longo prazo, o que importa é que a capacidade existe e continuará evoluindo — independentemente de quem sobreviva comercialmente.</p>
<p>Não há como retroceder... Mesmo que a tal "Bolha da IA" exploda, os modelos, os datasets, projetos open-source e repositórios continuarão existindo, nada impedirá ninguém de baixar um modelo (específico para sua necessidade) e rodar em sua máquina pessoal, home-server, VPS ou conta em algum cloud provider.</p>
<h2 id="heading-democratizacao-e-centralizacao">Democratização e centralização</h2>
<p>Essa tecnologia é importante demais para ficar nas mãos de poucas empresas. Por enquanto, existe uma democratização suficiente: modelos abertos — especialmente os produzidos na China — continuam competindo com modelos de fronteira de laboratórios fechados. O fato de OpenAI, Anthropic e Google estarem tão próximos em resultados há anos sugere não haver “mágica” proprietária suficiente para impedir que outros alcancem o mesmo nível.</p>
<h2 id="heading-o-conselho-pratico">O conselho prático</h2>
<p>Não importa o que você acredite sobre o que deveria ser o “certo” — você não pode controlar a situação recusando o que está acontecendo. Ignorar a IA não vai ajudar você nem sua carreira.</p>
<p>Teste essas ferramentas com seriedade. Semanas de trabalho real, não um teste de cinco minutos onde você apenas reforça suas próprias crenças. Encontre uma maneira de se multiplicar. Se não funcionar, tente novamente a cada poucos meses — a evolução é rápida.</p>
<p>E sim, talvez você tenha trabalhado muito para aprender a programar, e agora máquinas fazem boa parte do trabalho por você. Mas pense no que realmente te motivava quando ficava até de madrugada codando: era construir. E agora você pode construir mais e melhor, se encontrar uma forma eficaz de usar IA.</p>
<p>A diversão continua lá, intocada.</p>
<h2 id="heading-pare-de-chamar-tudo-de-vibe-coding">Pare de chamar tudo de “Vibe Coding”</h2>
<p>Existe uma confusão proposital — ou preguiçosa — em chamar qualquer uso de IA para gerar código de “vibe coding”. Vibe coding é quando alguém descreve o que quer em termos vagos, aceita o que o LLM cuspir, e no máximo reporta que algo não funcionou. O vibe coder não entende o código, não direciona a arquitetura, não intervém no design. E tudo bem — isso tem seu lugar e democratiza a criação de software para quem não é programador.</p>
<p>Mas quando um programador experiente usa IA como ferramenta de produção — com visão clara do que precisa ser feito, direcionando o design, revisando a saída, intervindo na implementação quando necessário e aplicando o resultado em ambiente controlado — isso não é “vibe coding”.</p>
<p>Segundo o <a target="_blank" href="https://antirez.com/news/159">Antirez</a>, isso é <strong>programação automática</strong>: o software segue a visão do produtor, e o código gerado é dele. Precisamos de outro termo porque a diferença não é cosmética, é qualitativa. Os resultados de um mesmo LLM variam drasticamente dependendo de quem está no comando — da intuição, do direcionamento contínuo e da ideia de software que o humano carrega.</p>
<p>Chamar ambos os processos pelo mesmo nome apaga essa distinção e, de quebra, desvaloriza o trabalho de quem sabe o que está fazendo.</p>
<p>Os dados de pré-treinamento foram produzidos por humanos. O código aberto que alimentou esses modelos é nosso presente coletivo — e o que fazemos com essa capacidade amplificada é produção nossa. Programação agora é automática. Visão, ainda não.</p>
<p>LLMs nos ajudarão a escrever software melhor, mais rápido, e permitirão que equipes pequenas compitam com empresas maiores — da mesma forma que o software de código aberto fez nos anos 90. O código aberto democratizou o acesso à infraestrutura. A IA está democratizando a capacidade de construir sobre ela.</p>
<p>Referências:</p>
<p>Automatic programming - <a target="_blank" href="https://antirez.com/news/159">https://antirez.com/news/159</a></p>
<p>Don't fall into the anti-AI hype - <a target="_blank" href="https://antirez.com/news/158">https://antirez.com/news/158</a></p>
]]></content:encoded></item><item><title><![CDATA[AI Coding com Agents Locais e Open Source]]></title><description><![CDATA[Se você trabalha com infraestrutura, automação ou desenvolvimento, provavelmente já percebeu que 2025 é o ano em que os AI coding agents deixaram de ser curiosidade para se tornarem ferramentas de produção. A diferença entre um agente e um simples au...]]></description><link>https://esli.blog.br/ai-coding-com-agents-locais-e-open-source</link><guid isPermaLink="true">https://esli.blog.br/ai-coding-com-agents-locais-e-open-source</guid><category><![CDATA[AI]]></category><category><![CDATA[agentic AI]]></category><category><![CDATA[agents]]></category><category><![CDATA[llm]]></category><category><![CDATA[code]]></category><category><![CDATA[SRE]]></category><category><![CDATA[Devops]]></category><category><![CDATA[self-hosted]]></category><dc:creator><![CDATA[Esli Silva]]></dc:creator><pubDate>Wed, 14 Jan 2026 15:58:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/kE0JmtbvXxM/upload/6e354dcc4de27ea51f874859c90bd3a5.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Se você trabalha com infraestrutura, automação ou desenvolvimento, provavelmente já percebeu que 2025 é o ano em que os AI coding agents deixaram de ser curiosidade para se tornarem ferramentas de produção. A diferença entre um agente e um simples autocomplete? O agente executa. Ele não apenas sugere código — ele cria arquivos, roda comandos, debugga erros e faz commits. Tudo isso enquanto você toma café (ou apaga incêndios em produção, porque SRE é assim).</p>
<p>Para quem trabalha com SRE/DevOps, o apelo é óbvio: automação de tarefas repetitivas, geração de scripts de migração, troubleshooting de configurações Terraform, análise de logs, criação de runbooks. A possibilidade de rodar tudo localmente — sem enviar código proprietário ou dados sensíveis para APIs externas — é o que separa essas ferramentas das alternativas SaaS. Compliance, air-gapped environments, dados de clientes: tudo isso importa quando você é responsável pela infraestrutura.</p>
<p>Este artigo lista as principais ferramentas open source disponíveis, organizadas por categoria. O foco é praticidade: o que cada uma faz, onde roda, e por que você deveria (ou não) considerar.</p>
<h2 id="heading-plataformas-de-inferencia-local-llm-runners">Plataformas de Inferência Local (LLM Runners)</h2>
<p>Antes de rodar qualquer agente, você precisa de um runtime para executar os modelos. Estas são as fundações:</p>
<p><strong>Ollama</strong> — <a target="_blank" href="https://ollama.ai">https://ollama.ai</a><br />Runtime minimalista para execução de LLMs locais via CLI. Um <code>ollama run llama3</code> e você tem um modelo rodando. API compatível com OpenAI, o que significa que qualquer ferramenta que fale com a API da OpenAI pode apontar para seu Ollama local. Suporta tool calling nativo, essencial para agentes. Para SRE, é a forma mais rápida de ter um LLM disponível para scripts, pipelines ou integração com outras ferramentas. Deploy via binário ou container Docker.</p>
<p><strong>LocalAI</strong> — <a target="_blank" href="https://localai.io">https://localai.io</a><br />Se Ollama é o canivete suíço, LocalAI é a caixa de ferramentas completa. Drop-in replacement para a API OpenAI, mas vai além: suporta geração de imagens, áudio, transcrição (Whisper), text-to-speech. O módulo LocalAGI adiciona capacidade de agentes autônomos; LocalRecall oferece busca semântica. Funciona em CPU — não exige GPU. Ideal para ambientes on-premise onde você quer uma stack AI completa sem depender de cloud.</p>
<p><strong>LM Studio</strong> — <a target="_blank" href="https://lmstudio.ai">https://lmstudio.ai</a><br />Interface gráfica para download e execução de modelos do Hugging Face. Servidor OpenAI-compatible embutido. Closed-source mas gratuito para uso pessoal. Útil para testar modelos antes de colocar em produção, ou para membros da equipe que preferem GUI. Otimizado para Apple Silicon e NVIDIA.</p>
<p><strong>Jan</strong> — <a target="_blank" href="https://jan.ai">https://jan.ai</a><br />Alternativa 100% open-source ao ChatGPT para execução offline. Desktop app com download de modelos integrado, API local compatível com OpenAI (porta 1337 por padrão). Zero telemetria, dados armazenados localmente. Para quem precisa de uma interface amigável mas não quer abrir mão do controle.</p>
<p><strong>GPT4All</strong> — <a target="_blank" href="https://gpt4all.io">https://gpt4all.io</a><br />Focado em rodar LLMs quantizados em hardware consumer-grade. Suporta 100+ modelos, interface desktop multiplataforma. A proposta é democratização: rodar AI em qualquer máquina, sem requisitos de hardware exóticos.</p>
<p><strong>AnythingLLM</strong> — <a target="_blank" href="https://anythingllm.com">https://anythingllm.com</a><br />Workspace para RAG (Retrieval-Augmented Generation) e chat com documentos. Conecta com múltiplos providers (Ollama, OpenAI, Azure), vector stores integrados, AI agents com tool calling. Deploy via Docker ou desktop app. Para SRE, é interessante para criar bases de conhecimento pesquisáveis sobre runbooks, documentação de infra, post-mortems.</p>
<h2 id="heading-agentes-de-codigo-para-terminal-e-ides">Agentes de Código para Terminal e IDEs</h2>
<p>Para quem vive no terminal, estas ferramentas integram AI diretamente no fluxo de trabalho CLI:</p>
<p><strong>Aider</strong> — <a target="_blank" href="https://aider.chat">https://aider.chat</a> | <a target="_blank" href="https://github.com/Aider-AI/aider">https://github.com/Aider-AI/aider</a><br />Pair programming no terminal. O Aider mapeia seu codebase completo, entende a estrutura do projeto, e faz edições cirúrgicas. Commits automáticos com mensagens descritivas. Suporta 30+ linguagens e qualquer LLM (Claude, GPT-4, modelos locais via Ollama). Top scores no SWE-Bench, o benchmark mais respeitado para coding agents. Para SRE: ideal para refatorar scripts Terraform, atualizar Ansible playbooks, ou gerar testes para módulos de infraestrutura. O fluxo é simples: <code>aider arquivo.tf</code>, descreve o que quer, e o Aider aplica as mudanças diretamente.</p>
<p><strong>Open Interpreter</strong> — <a target="_blank" href="https://openinterpreter.com">https://openinterpreter.com</a> | <a target="_blank" href="https://github.com/openinterpreter/open-interpreter">https://github.com/openinterpreter/open-interpreter</a><br />Interface natural language para seu computador. Diferente de outros agentes que só editam código, o Open Interpreter executa: roda scripts, manipula arquivos, interage com APIs, instala pacotes. Você descreve o que quer em linguagem natural; ele traduz para comandos e executa. Suporta modelos locais via Ollama/LM Studio. Para DevOps, é útil para tarefas ad-hoc: "analise os logs do nginx das últimas 24h e me diga quais IPs geraram mais 5xx" ou "crie um script que faça backup incremental desses diretórios para S3".</p>
<p><strong>OpenCode</strong> — <a target="_blank" href="https://opencode.ai">https://opencode.ai</a> | <a target="_blank" href="https://github.com/sst/opencode">https://github.com/sst/opencode</a><br />CLI com TUI (Terminal User Interface) construída em Go. 60k+ stars, usado por 650k+ devs/mês. Suporta múltiplos providers (OpenAI, Anthropic, Gemini, Bedrock, Groq, Azure, modelos locais). Session management persistente com SQLite, integração LSP para code intelligence. Diferencial: integração com GitHub Actions — você pode invocar o OpenCode em PRs e issues via comentários. Plan mode para revisar mudanças antes de aplicar. Disponível também como desktop app.</p>
<p><strong>Goose (Block)</strong> — <a target="_blank" href="https://block.github.io/goose">https://block.github.io/goose</a> | <a target="_blank" href="https://github.com/block/goose">https://github.com/block/goose</a><br />Framework de agentes da Block (a empresa por trás do Square e Cash App). Escrito em Rust, executa 100% local. Vai além de código: instala dependências, executa comandos, testa, debugga, interage com APIs externas. Suporte completo a MCP (Model Context Protocol) — o padrão da Anthropic para extensibilidade de ferramentas. Desktop app e CLI. Agnóstico ao modelo. A Block reportou que engenheiros internos economizam ~20% do tempo em tarefas de manutenção usando o Goose. O fato de ser open-source (Apache 2.0) e ter backing de uma empresa do porte da Block dá confiança para uso enterprise.</p>
<p><strong>Plandex</strong> — <a target="_blank" href="https://plandex.ai">https://plandex.ai</a> | <a target="_blank" href="https://github.com/plandex-ai/plandex">https://github.com/plandex-ai/plandex</a><br />Agente para projetos grandes. Suporta 2M tokens de contexto efetivo, diff review em sandbox isolado (mudanças ficam separadas do projeto até você aprovar), commits controlados. Combina modelos de múltiplos providers. Terminal-based workflow robusto para quem trabalha com codebases extensos. <em>Nota: a versão cloud foi descontinuada em outubro/2025, mas funciona self-hosted com Docker ou servidor próprio.</em></p>
<p><strong>Cline</strong> — <a target="_blank" href="https://cline.bot">https://cline.bot</a> | <a target="_blank" href="https://github.com/cline/cline">https://github.com/cline/cline</a><br />O agente open-source mais popular para VSCode, com 4M+ de downloads. Funciona em dois modos: Plan (planeja as mudanças) e Act (executa). Human-in-the-loop obrigatório — cada mudança requer aprovação, o que é bom para ambientes onde você não quer surpresas. Executa comandos no terminal integrado, browser automation para testes, criação/edição de arquivos. Extensível via MCP: você pode criar ferramentas customizadas ("add a tool that fetches Jira tickets" e o Cline cria e instala o MCP server). Suporta qualquer provider: OpenRouter, Anthropic, OpenAI, Gemini, Bedrock, Ollama, LM Studio.</p>
<p><strong>Roo Code</strong> — <a target="_blank" href="https://roocode.com">https://roocode.com</a> | <a target="_blank" href="https://github.com/RooCodeInc/Roo-Code">https://github.com/RooCodeInc/Roo-Code</a><br />Fork do Cline com foco em multi-agent workflows. A ideia é ter um "time" de agentes especializados: Architect (planeja estrutura), Code (implementa), Debug (investiga erros), Ask (responde perguntas). Você pode criar Custom modes ilimitados: QA Engineer, Product Manager, Security Auditor — cada um com prompts e ferramentas específicas. Suporte a VSCode e JetBrains. O Roo Cloud permite delegar trabalho para agentes rodando remotamente, acionáveis via Slack ou GitHub. Para equipes de platform engineering, a possibilidade de ter agentes especializados em diferentes aspectos (segurança, performance, compliance) é interessante.</p>
<p><strong>Kilo Code</strong> — <a target="_blank" href="https://kilo.ai">https://kilo.ai</a> | <a target="_blank" href="https://github.com/Kilo-Org">https://github.com/Kilo-Org</a><br />Lançado em março/2025, já acumulou 250k+ instalações e 10k+ stars. Diferencial: suporta 400+ modelos sem necessidade de configurar API keys (provider integrado opcional). Orchestrator mode decompõe tarefas complexas em subtasks executados por agentes especializados. Memory Bank mantém contexto persistente entre sessões. Suporta VSCode, JetBrains, Cursor, Windsurf e CLI standalone.</p>
<p><strong>Continue</strong> — <a target="_blank" href="https://continue.dev">https://continue.dev</a> | <a target="_blank" href="https://github.com/continuedev/continue">https://github.com/continuedev/continue</a><br />Plataforma para criar assistentes AI customizáveis. 26k+ stars. Três modos: Chat (conversa sobre código), Plan (cria plano de implementação), Agent (executa mudanças). CLI com TUI e modo headless para CI/CD. Configuração via <code>.continue/rules/</code> permite definir padrões de equipe que o AI segue. Integração MCP com GitHub, Sentry, Snyk, Linear — o agente pode buscar contexto de issues, alertas de segurança, erros de produção. Para DevOps, a possibilidade de rodar em modo headless dentro de pipelines CI/CD abre cenários interessantes: code review automatizado, geração de changelog, atualização de documentação.</p>
<p><strong>Qodo Gen</strong> (anteriormente Codium) — <a target="_blank" href="https://www.qodo.ai">https://www.qodo.ai</a><br />Plataforma "quality-first" com 751k instalações no VSCode. Foco em geração de código, testes unitários e documentação com ênfase em code correctness. Menos autônomo que outros — a proposta é assistência com garantia de qualidade, não automação total. Para times que precisam de cobertura de testes mas não têm tempo de escrever, é uma opção pragmática.</p>
<h2 id="heading-plataformas-low-code-no-code-para-agentes">Plataformas Low-Code / No-Code para Agentes</h2>
<p>Para quem prefere construir workflows visualmente ou precisa de algo mais acessível para membros não-técnicos da equipe:</p>
<p><strong>n8n</strong> — <a target="_blank" href="https://n8n.io">https://n8n.io</a> | <a target="_blank" href="https://github.com/n8n-io/n8n">https://github.com/n8n-io/n8n</a><br />Plataforma de automação visual com 400+ integrações e suporte nativo a AI agents via LangChain. Self-hosted, fair-code license. Combina workflows tradicionais (webhooks, APIs, bancos de dados) com capacidades de LLM e RAG. Para SRE, é útil para criar automações que combinam AI com sistemas existentes: "quando um alerta do PagerDuty chegar, busque logs relacionados, gere um resumo, e poste no canal do Slack". A curva de aprendizado é menor que escrever tudo em código.</p>
<p><strong>Flowise</strong> — <a target="_blank" href="https://flowiseai.com">https://flowiseai.com</a> | <a target="_blank" href="https://github.com/FlowiseAI/Flowise">https://github.com/FlowiseAI/Flowise</a><br />Builder visual drag-and-drop para aplicações LLM, baseado em LangChain. Suporta RAG, chatbots, agents com tool calling. Deploy via Docker, API REST exposta automaticamente. Interface amigável para prototipagem rápida. Útil para criar POCs de assistentes internos antes de investir em desenvolvimento custom.</p>
<p><strong>Langflow</strong> — <a target="_blank" href="https://langflow.org">https://langflow.org</a> | <a target="_blank" href="https://github.com/langflow-ai/langflow">https://github.com/langflow-ai/langflow</a><br />Plataforma low-code para AI agents e MCP servers. Editor visual Python-based. Self-hosted only (MIT license). Mais técnico que Flowise, com maior flexibilidade para customização.</p>
<p><strong>Dify</strong> — <a target="_blank" href="https://dify.ai">https://dify.ai</a> | <a target="_blank" href="https://github.com/langgenius/dify">https://github.com/langgenius/dify</a><br />Plataforma all-in-one com 114k+ stars. Visual workflow builder, RAG pipelines, agent capabilities, observability integrada. Suporta deploy local ou cloud, múltiplos LLM providers. Para times que querem uma solução completa sem montar stack from scratch.</p>
<h2 id="heading-frameworks-de-agentes-multi-purpose">Frameworks de Agentes Multi-Purpose</h2>
<p>Para quem quer construir sistemas de agentes customizados ou precisa de mais controle:</p>
<p><strong>AutoGPT</strong> — <a target="_blank" href="https://agpt.co">https://agpt.co</a> | <a target="_blank" href="https://github.com/Significant-Gravitas/AutoGPT">https://github.com/Significant-Gravitas/AutoGPT</a><br />Um dos primeiros frameworks de agentes autônomos, com 177k+ stars. Plataforma low-code para criação de agentes goal-driven. Interface visual drag-and-drop, execução contínua em cloud (ou self-hosted), suporte a múltiplas ferramentas. A proposta é definir um objetivo e deixar o agente decompor em subtasks e executar autonomamente. Comunidade ativa, mas requer cuidado com autonomia excessiva em ambientes de produção.</p>
<p><strong>CrewAI</strong> — <a target="_blank" href="https://crewai.com">https://crewai.com</a> | <a target="_blank" href="https://github.com/crewAIInc/crewAI">https://github.com/crewAIInc/crewAI</a><br />Framework Python para sistemas multi-agente com abstração de "crews" (equipes). Cada agente tem role/goal/backstory específicos e colaboram em workflows estruturados. CrewAI Studio oferece interface visual. Ideal para simular equipes: um agente pesquisa, outro analisa, outro implementa. Para DevOps, pode ser usado para criar pipelines de análise onde diferentes agentes cuidam de aspectos específicos (segurança, performance, compliance).</p>
<p><strong>LangChain / LangGraph</strong> — <a target="_blank" href="https://langchain.com">https://langchain.com</a> | <a target="_blank" href="https://github.com/langchain-ai/langchain">https://github.com/langchain-ai/langchain</a><br />Framework modular para construção de aplicações LLM. LangGraph adiciona orchestration baseada em grafos com estado persistente, branching e error recovery. Fundação para muitas das ferramentas listadas aqui. Mais baixo nível — você constrói os agentes em vez de usar prontos.</p>
<p><strong>AutoGen (Microsoft)</strong> — <a target="_blank" href="https://microsoft.github.io/autogen">https://microsoft.github.io/autogen</a> | <a target="_blank" href="https://github.com/microsoft/autogen">https://github.com/microsoft/autogen</a><br />Framework event-driven para sistemas multi-agente com conversação estruturada. Suporta workflows determinísticos e dinâmicos, extensível via MCP servers. Foco em colaboração entre agentes especializados. Backing da Microsoft dá credibilidade para uso enterprise.</p>
<p><strong>MetaGPT</strong> — <a target="_blank" href="https://github.com/geekan/MetaGPT">https://github.com/geekan/MetaGPT</a><br />Simula estrutura de empresa de software com agentes assumindo roles: PM, Architect, Engineer, QA. Gera documentação, código e testes de forma coordenada. Interessante para prototipagem de features completas.</p>
<h2 id="heading-ferramentas-especializadas">Ferramentas Especializadas</h2>
<p><strong>PrivateGPT</strong> — <a target="_blank" href="https://privategpt.io">https://privategpt.io</a> | <a target="_blank" href="https://github.com/zylon-ai/private-gpt">https://github.com/zylon-ai/private-gpt</a><br />API production-ready para RAG 100% privado. Ingestion de documentos, chat contextual, tudo offline. Baseado em LlamaIndex, API compatível com OpenAI. Para ambientes com dados sensíveis onde nada pode sair da rede. Casos de uso: chat com documentação interna, análise de logs confidenciais, base de conhecimento para runbooks.</p>
<p><strong>Huginn</strong> — <a target="_blank" href="https://github.com/huginn/huginn">https://github.com/huginn/huginn</a><br />Plataforma self-hosted para criação de agentes que monitoram web, coletam dados e executam ações baseadas em triggers. Inspirado no IFTTT mas totalmente controlável. Mais voltado para automação de data pipelines e monitoramento do que coding, mas útil no toolkit de SRE.</p>
<p><strong>OpenHands</strong> (anteriormente OpenDevin) — <a target="_blank" href="https://github.com/All-Hands-AI/OpenHands">https://github.com/All-Hands-AI/OpenHands</a><br />Agente autônomo de engenharia de software. Opera em nível de repositório, faz changes multi-file, executa testes em sandbox, debugging iterativo. Mais autônomo que a maioria — a proposta é delegar features inteiras.</p>
<h2 id="heading-comparativo-resumido">Comparativo Resumido</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Ferramenta</td><td>Ambiente</td><td>Foco</td><td>Self-hosted</td><td>MCP Support</td></tr>
</thead>
<tbody>
<tr>
<td>Aider</td><td>Terminal</td><td>Pair programming</td><td>✓</td><td>✗</td></tr>
<tr>
<td>Open Interpreter</td><td>Terminal</td><td>Execução geral</td><td>✓</td><td>✗</td></tr>
<tr>
<td>OpenCode</td><td>Terminal/Desktop/IDE</td><td>Coding agent</td><td>✓</td><td>✓</td></tr>
<tr>
<td>Goose</td><td>Terminal/Desktop</td><td>Agente extensível</td><td>✓</td><td>✓</td></tr>
<tr>
<td>Cline</td><td>VSCode</td><td>IDE agent</td><td>✓</td><td>✓</td></tr>
<tr>
<td>Roo Code</td><td>VSCode/JetBrains</td><td>Multi-agent IDE</td><td>✓</td><td>✓</td></tr>
<tr>
<td>Kilo Code</td><td>VSCode/JetBrains/CLI</td><td>Orchestration</td><td>✓</td><td>✓</td></tr>
<tr>
<td>Continue</td><td>VSCode/JetBrains/CLI</td><td>Customizable</td><td>✓</td><td>✓</td></tr>
<tr>
<td>n8n</td><td>Web UI</td><td>Workflow automation</td><td>✓</td><td>Via integração</td></tr>
<tr>
<td>Flowise</td><td>Web UI</td><td>Visual RAG/agents</td><td>✓</td><td>Via integração</td></tr>
</tbody>
</table>
</div><hr />
<h2 id="heading-conclusao">Conclusão</h2>
<p>O ecossistema de AI coding agents open source amadureceu significativamente. Não estamos mais falando de demos interessantes ou projetos de fim de semana — são ferramentas com milhões de usuários, backing de empresas como Block e Microsoft, e comunidades ativas de contribuidores.</p>
<p>Para SRE/DevOps, o valor está em três frentes:</p>
<ol>
<li><p><strong>Automação de tarefas repetitivas</strong>: geração de scripts, atualização de configurações, migração de código. O tempo que você gastaria escrevendo um script de migração de Terraform pode ser reduzido drasticamente.</p>
</li>
<li><p><strong>Troubleshooting assistido</strong>: análise de logs, correlação de eventos, sugestão de fixes. Quando são 3h da manhã e você está olhando para um stack trace incompreensível, ter um assistente que entende o contexto do seu codebase ajuda.</p>
</li>
<li><p><strong>Documentação e conhecimento</strong>: RAG sobre runbooks, post-mortems, documentação de arquitetura. A maioria das equipes tem conhecimento tribal que nunca foi documentado adequadamente. Ferramentas como PrivateGPT ou AnythingLLM permitem criar bases pesquisáveis sem expor dados sensíveis.</p>
</li>
</ol>
<p>A execução local é o diferencial crítico. Em ambientes enterprise, enviar código para APIs externas frequentemente não é opção. A combinação de Ollama (ou LocalAI) com qualquer dos agentes listados permite operação 100% on-premise, air-gapped se necessário.</p>
<p>Minha recomendação para quem está começando:</p>
<ul>
<li><p><strong>Para terminal</strong>: comece com Aider. É maduro, bem documentado, e o fluxo é intuitivo.</p>
</li>
<li><p><strong>Para IDE</strong>: Cline é o mais estabelecido. Roo Code se você quer experimentar multi-agent.</p>
</li>
<li><p><strong>Para automação visual</strong>: n8n se você já trabalha com workflows; Flowise se o foco é RAG.</p>
</li>
<li><p><strong>Para rodar modelos locais</strong>: Ollama. Simples, funciona, comunidade grande.</p>
</li>
</ul>
<p>O MCP (Model Context Protocol) está se tornando o padrão de fato para extensibilidade. Se você for investir tempo aprendendo uma tecnologia, MCP é onde eu colocaria fichas. A maioria das ferramentas novas já suporta, e a tendência é consolidação em torno desse protocolo.</p>
<p>Por fim: essas ferramentas são tão boas quanto o modelo que você usa e o contexto que você fornece. Um agente com um modelo fraco ou sem acesso ao contexto relevante vai gerar lixo. A engenharia de prompts e a curadoria do que o agente pode acessar continuam sendo responsabilidade sua.</p>
<p>O futuro é agentic. A questão não é se você vai usar essas ferramentas, mas quando — e se vai ser com controle sobre seus dados ou entregue para um SaaS.</p>
]]></content:encoded></item></channel></rss>