Três Soluções de Arquitetura para SaaS B2B Multi-tenant que Eu Gostaria de Ter Conhecido Antes

Um artigo detalhado sobre como implementar multi-tenancy em aplicações SaaS B2B, abordando soluções para problemas comuns como double-booking, segurança de dados e conformidade com regulamentações. O autor compartilha suas experiências e lições aprendidas, incluindo o uso de tenant_id, EXCLUDE USING gist e argon2id.

MundiX News·13 de maio de 2026·10 min de leitura·👁 4 views

Isaev1980 42 minutos atrás Três soluções de arquitetura para SaaS B2B multi-tenant que eu gostaria de ter conhecido antes Médio 10 min 1.6K Python * PostgreSQL * Segurança da Informação * Programação * Caso Da caixa de areia O erro mais caro do meu SaaS B2B teve exatamente uma linha

python
  # app/config.py
  TENANT_ID = "tenant-1"

Quando eu tinha um tenant, tudo funcionava corretamente. No segundo — metade das entidades de administração (médicos, serviços, tabelas de preços) começou a desaparecer da interface do cliente. Não "não salvar" — mas aparecer no banco de dados com outro tenant_id . Eu fiquei olhando para essa mística por um dia e meio, antes de perceber: 30 endpoints pegam tenant_id da closure de config , e não de user.tenant_id . Óbvio em retrospectiva. Completamente invisível durante o primeiro piloto. Esta análise é sobre três soluções de arquitetura para SaaS multi-tenant em uma indústria regulamentada, que são tomadas na primeira semana e, em seguida, por anos, economizam meses de refatoração ou acumulam silenciosamente dívida técnica. Stack: Python 3.11 / FastAPI / SQLAlchemy 2.x / PostgreSQL 16. Contexto: SaaS B2B para clínicas médicas privadas, 152-FZ, agendamento em tempo real. TL;DR

  • Multi-tenancy via tenant_id column + helper scoped_select do primeiro commit — mesmo que haja apenas um tenant. A razão está dentro.
  • Proteção contra double-booking via PostgreSQL EXCLUDE USING gist + tsrange — números reais: 12 solicitações concorrentes por slot → 1×200, 11×409, sem application-level locks.
  • 152-FZ — são campos e helpers : data_category enum em audit_logs com autoclassificador, migração transparente de PBKDF2 para argon2id sem forced reset, patient_consents com versionamento scoped.
  • Um bug com TENANT_ID hardcoded mostra por que todas as três soluções precisam ser implementadas imediatamente.
  • Operational tooling : verificação de integridade somente leitura em sete categorias de anomalias + detecção de schema drift via alembic check em um PG limpo. Solução nº 1: multi-tenancy via tenant_id column Três abordagens clássicas para multi-tenancy em um banco de dados relacional: Estratégia Isolamento Backup/migrações Custo Quando se encaixa Schema-per-tenant No nível do Postgres Complexo (N esquemas × M migrações) Médio 5–50 tenants empresariais com diferentes SLA Database-per-tenant Ferro Muito complexo Alto Compliance-driven, ≤10 tenants Shared DB + tenant_id No nível do aplicativo Simples (um esquema) Baixo SMB SaaS, centenas–milhares de tenants Eu escolhi a terceira opção. Cada tabela de negócios contém tenant_id TEXT NOT NULL com um índice, todas as consultas devem filtrar por ele. O preço dessa simplicidade — um único erro no filtro se transforma em um IDOR em dados confidenciais entre tenants. Para não esquecer disso, o projeto tem um helper sutil:
python
# app/tenant_scope.py
from sqlalchemy import select
from sqlalchemy.sql import Select

def scoped_select(model, user) -> Select:
    """SELECT, automaticamente limitado ao tenant atual.

    Lança PermissionError se o usuário não tiver tenant_id — isso é
    intencional: é melhor um 500 nos logs do que um vazamento silencioso.
    """
    if not user.tenant_id:
        raise PermissionError("User has no tenant_id; refusing to query")
    return select(model).where(model.tenant_id == user.tenant_id)


def scoped_get(db, model, id_, user):
    return db.scalar(
        select(model).where(model.id == id_, model.tenant_id == user.tenant_id)
    )

O princípio — é melhor um erro explícito do que um vazamento silencioso. E na revisão de código, a regra é simples: qualquer select(BusinessModel) sem scoped_select — uma observação de bloqueio. Bug story em callout: uma linha, dois dias de debug Na primeira versão, eu usei o closure tenant_id do config em todos os write-handlers:

python
> @router.post("/v1/doctors")
> def create_doctor(payload, db, user):
>     item = Doctor(
>         id=f"doctor-{uuid4()}",
>         tenant_id=tenant_id,           # ← closure do config!
>         **payload.model_dump(),
>     )
> ```
O read-path usou
scoped_select(Doctor, user)
— corretamente. O write-path bugou
config.TENANT_ID
. Enquanto houver apenas um tenant — a dessincronização é invisível. Quando conectamos a segunda clínica, seu administrador viu a lista de médicos vazia, embora tivesse acabado de adicionar três. Esses três estavam no banco de dados com
tenant_id="tenant-1"
. Fix: 
tenant_id=user.tenant_id
e regressão em E2E “registrar tenant B → criar entidade como user-B → logar como user-A → certificar-se de que não é visto”.
Lição: o helper é necessário desde o primeiro commit, mesmo que haja apenas um tenant. No décimo tenant, é tarde demais — você terá que revisar cada endpoint.
E por que não PostgreSQL Row-Level Security?
Esta é a primeira pergunta que me fazem, e ela é justa. RLS daria isolamento de tenant no nível do banco de dados, e não do aplicativo — teoricamente mais confiável. Na prática, RLS requer
SET app.tenant_id = '...'
no início de cada transação, quebra o stateless connection pooling (PgBouncer em modo de transação se torna mais difícil de configurar) e não funciona bem com migrações e tarefas de administração, onde você quer contornar a restrição legalmente. Para um projeto solo em estágio inicial, a sobrecarga de RLS não é justificada —
scoped_select
+ regra de lint na revisão de código dá 95% de proteção com 5% de complexidade. Em um estágio posterior (dezenas de tenants empresariais com requisitos de conformidade), RLS se torna um complemento razoável, não uma substituição.
Solução nº 2: PostgreSQL
EXCLUDE USING gist
contra double-booking
Dois administradores reservam simultaneamente o mesmo slot com o mesmo médico. Ambos veem o slot livre. Ambos chamam
POST /appointments
. Ambos recebem
200 OK
. Dupla gravação.
A proteção “no código” (
SELECT
para verificação →
) sob carga paralela não funciona. Entre duas solicitações na mesma transação, outra transação consegue inserir um slot sobreposto. Eu vi isso no primeiro teste de carga.
A evolução da proteção no projeto ocorreu em três estágios. Apresento números reais de benchmarks no PostgreSQL 16, single-node:
Estágio 1 — application-level check.
12 solicitações concorrentes por slot →
4×200, 8×409
. Gravações duplas visíveis.
create_unique_appointments
p95 = 26ms.
Estágio 2 — transactional advisory locks
(
pg_advisory_xact_lock
por
(doctor_id, time_window)
antes de INSERT).
12 concorrentes →
1×200, 11×409
. Race-condition fechado, mas
create_unique_appointments
p95 subiu para
36.86ms
devido à sobrecarga de serialização.
Estágio 3 — hard DB invariant via
EXCLUDE USING gist
. As mesmas 12 concorrentes →
1×200, 11×409
,
create_unique_appointments
p95 =
31.69ms
, conflict-path p95 =
11.22ms
. A proteção foi movida do aplicativo para o esquema, o advisory lock não é mais necessário.
Restrição DDL:
``sql
-- Alembic upgrade
CREATE EXTENSION IF NOT EXISTS btree_gist;

ALTER TABLE appointments ADD CONSTRAINT appointments_doctor_slot_excl
  EXCLUDE USING gist (
    doctor_id WITH =,
    tsrange(starts_at, ends_at, '[)') WITH &&
  )
  WHERE (status NOT IN ('cancelled', 'no_show'));

O que está acontecendo aqui:

  • doctor_id WITH = — dois intervalos são considerados conflitantes apenas se tiverem o mesmo doctor_id .
  • tsrange(starts_at, ends_at, '[)') — intervalo semiaberto; a entrada 10:00–10:30 e 10:30–11:00 não se sobrepõem.
  • && — operador de interseção de intervalos.
  • WHERE (status NOT IN ('cancelled', 'no_show')) — cancelados e não comparecimentos são excluídos, o paciente após o cancelamento pode se reinscrever no mesmo slot. btree_gist é necessário porque = para escalar doctor_id via o operador gist padrão não funciona; a extensão adiciona semântica btree dentro do índice gist. Mapeamento de erros em HTTP no FastAPI: ``python from psycopg.errors import ExclusionViolation

try: db.add(appointment) db.flush() except IntegrityError as exc: if isinstance(exc.orig, ExclusionViolation): raise HTTPException( status_code=409, detail={ "code": "APPOINTMENT_SLOT_CONFLICT", "message": "O slot está ocupado por outra entrada", }, ) raise

tsrange
ou
tstzrange
?
Eu escolhi
tsrange
(timestamp ingênuo sem fuso horário), porque neste projeto todos os timestamps são armazenados em UTC, e a conversão para o horário local da clínica é feita no nível do aplicativo via
tenant.timezone
.
tstzrange
funcionaria, mas adicionaria uma camada extra de conversões implícitas e possíveis bugs com DST. Se você tiver a política de armazenamento “timestamp with timezone em todos os lugares” — pegue
tstzrange
, a diferença é apenas em como o Postgres internamente trata os intervalos.
Armadilhas:
- EXCLUDE
cria um índice gist, que cresce mais rápido que B-tree em grandes volumes. De acordo com o [artigo no Habr sobre btree_gist benchmark](https://habr.com/ru/articles/820455/) — degradação de gravação para 2× e leitura para 20% em tabelas quentes. Para uma tabela de registros de pacientes, isso é ok (cardinalidade baixa), para uma tabela de eventos com milhões de linhas — pense nisso.
- WHERE
a cláusula partial constraint funciona apenas em / DELETE. O cancelamento deve ser
UPDATE status='cancelled'
, não
DELETE
— caso contrário, a entrada “desaparece”, e o slot em um segundo é ocupado por outra pessoa, e a entrada cancelada não pode mais ser restaurada.
- Nos testes, você precisa do mesmo dialeto (PG, não SQLite). SQLite aceita DDL sem erros, mas não cria nenhuma restrição de exclusão — o bug nos testes não pode ser rastreado.
O que eu consegui no final: com o crescimento de 1 para 10 clínicas na produção, nenhuma gravação dupla. Não precisa de Redis, não precisa de distributed lock, não precisa de application-level retry. Pos­tgreSQL faz todo o trabalho.
Solução nº 3: 152-FZ como código
Para dados médicos na Federação Russa, 152-FZ exige: armazenamento em data centers russos, proteção de dados durante a transmissão e armazenamento, log de acesso a PII, consentimento separado para o processamento de categorias especiais, a capacidade de excluir/anonimizar mediante solicitação. O que disso se transforma em código:
Criptografia de senha: migração PBKDF2 → argon2id sem forced reset
Inicialmente, as senhas eram hashadas via
PBKDF2-HMAC-SHA256
com 120.000 iterações — o padrão OWASP até 2023. A recomendação moderna OWASP/NIST — argon2id (memory-hard, mais resistente a ataques de GPU). Uma migração acentuada via forced password reset é inaceitável em B2B (dezenas de funcionários da clínica, o registrador não poderá logar na manhã de segunda-feira), portanto, um esquema transparente funciona: novas senhas são escritas como argon2id, as antigas são verificadas em seu formato, com login bem-sucedido, são rehashadas silenciosamente em argon2id.
A chave — detecção de formato por prefixo de hash:
```python
import hashlib
import secrets
from argon2 import PasswordHasher
from argon2 import exceptions as argon2_exceptions

PASSWORD_ITERATIONS = 120_000  # legacy PBKDF2 para backward-compat
PASSWORD_PREFIX = "pbkdf2_sha256"
ARGON2_PREFIX = "$argon2"
PASSWORD_HASHER = PasswordHasher()  # argon2id com parâmetros padrão

def hash_password(password: str) -> str:
    """Todas as novas senhas — argon2id."""
    return PASSWORD_HASHER.hash(password)

def verify_password(password: str, encoded: str) -> bool:
    if encoded.startswith(ARGON2_PREFIX):
        try:
            return PASSWORD_HASHER.verify(encoded, password)
        except (argon2_exceptions.VerifyMismatchError,
                argon2_exceptions.InvalidHashError):
            return False
    if encoded.startswith(f"{PASSWORD_PREFIX}$"):
        _, iterations, salt, digest = encoded.split("$", 3)
        computed = hashlib.pbkdf2_hmac(
            "sha256", password.encode(), salt.encode(), int(iterations)
        )
        return secrets.compare_digest(computed.hex(), digest)
    return False

def password_needs_rehash(encoded: str) -> bool:
    if encoded.startswith(f"{PASSWORD_PREFIX}$"):
        return True  # qualquer PBKDF2 → upgrade em argon2id
    if encoded.startswith(ARGON2_PREFIX):
        return PASSWORD_HASHER.check_needs_rehash(encoded)
    return False

Em /auth/login após a verificação bem-sucedida:

python
if password_needs_rehash(user.password_hash):
    user.password_hash = hash_password(plain_password)
    db.commit()

Parâmetros argon2id e trade-off. Eu uso os padrões argon2-cffi : memory_cost=65536 (64 MiB), time_cost=3 , parallelism=4 . No meu VPS, isso dá uma latência de login de cerca de 80ms — aceitável para o usuário, caro para o atacante (força bruta na GPU se torna impraticável devido à natureza memory-bound do algoritmo). Se as clínicas piloto forem cerca de 100 logando simultaneamente, você pode reduzir memory_cost para 32 MiB, mas até agora eu não cheguei nem perto dessa restrição. Por que argon2id, e não bcrypt ou scrypt? bcrypt é estável, mas não memory-hard e perde para as fazendas de GPU. scrypt memory-hard, mas menos ajustável entre os trade-offs de latência/memória. argon2id — o vencedor da Password Hashing Competition 2015, recomendação OWASP desde 2023, e sua abordagem “híbrida” combina a resistência do argon2i a ataques de canal lateral com a resistência a GPU do argon2d. Para B2B regulamentado, este é um default razoável. Audit log com classificação de categorias de PII Cada operação com dados do paciente é escrita em audit_logs com o campo data_category . Este enum é necessário para que, mediante solicitação do sujeito (ou Roskomnadzor), você possa baixar apenas as categorias relevantes com um SELECT, e não analisar entity_type / action por linhas:

python
class AuditLog(Base):
    __tablename__ = "audit_logs"

    id: Mapped[str] = mapped_column(String, primary_key=True)
    tenant_id: Mapped[str] = mapped_column(String, index=True)
    actor_user_id: Mapped[Optional[str]] = mapped_column(String, nullable=True)
    entity_type: Mapped[str] = mapped_column(String)
    entity_id: Mapped[str] = mapped_column(String)
    action: Mapped[str] = mapped_column(String)
    # 152-FZ art. 10 p. 2 — marcação separada de categorias especiais de PII.
    data_category: Mapped[str] = mapped_column(String, default="general", index=True)
    before_json: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
    after_json: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
    ip: Mapped[Optional[str]] = mapped_column(String, nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=utcnow)

    __table_args__ = (
        Index("ix_audit_logs_tenant_created", "tenant_id", text("created_at DESC")),
    )

data_category — enum de três valores, que não é definido manualmente, mas por um classificador automático por entity_type:

python
_AUDIT_SPECIAL_HEALTH_ENTITIES = frozenset({
    "patient", "patient_consent",
    "appointment", "encounter", "notification",
    "compliance_retention",
})
_AUDIT_IDENTITY_ENTITIES = frozenset({"user", "user_group"})

def _classify_audit_entity(entity_type: str) -> str:
    if entity_type in _AUDIT_SPECIAL_HEALTH_ENTITIES:
        return "special_health"
    if entity_type in _AUDIT_IDENTITY_ENTITIES:
        return "identity"
    return "general"

special_health inclui não apenas diagnósticos — lá estão appointment e notification`, porque o próprio fato de se inscrever em um médico específico + o motivo do tratamento já são considerados uma categoria especial de PII em uma interpretação estrita da 152-FZ art. 10. Um classificador conservador é melhor do que uma subclassificação: se o regulador perguntar “quais dados de saúde você coleta” — é melhor errar para o lado de “mais” do que “menos”. Como 152-FZ difere do GDPR. O modelo não é transferido um para um: 152-FZ está mais próximo do HIPAA americano, pois destaca separadamente categorias especiais com requisitos adicionais para consentimento e armazenamento, além do requisito de residência (apenas data centers da Federação Russa) e registro obrigatório no registro de operadores PII no RKN. A estrutura do GDPR controller/processor/lawful-basis é semelhante em forma, mas o regulador e os documentos são diferentes. Operational tooling Duas ferramentas sem as quais eu não confiaria no banco de dados do projeto piloto.

  1. Read-only integrity check. Um script em sete estratégias, cada uma pegando uma classe de anomalias que a SQL-constraint não pega: Estratégia O que pega orphan-fk

tenant-scope Registros para pais inexistentes e vazamentos de FK entre tenants state-machine + date-invariants status='finalized' AND finalized_at IS NULL , ends_at <= starts_at logical-duplicates + soft-delete + audit-log Duplicatas de telefone/passaporte por tenant, anonimizadas com PII, data_category fora do enum É executado contra um restore local do dump de produção (não contra a própria produção — uma varredura de longa duração em tabelas quentes bloqueia os writers). Exit code 1 se houver descobertas — adequado como um CI-gate antes de uma grande migração. 2. Schema drift detection. Antes de cada lançamento — ciclo completo em um PG limpo:

bash
make postgres-up
DATABASE_URL=... alembic upgrade head
DATABASE_URL=... alembic check  # autogen diff contra modelos

alembic check não é ideal: não vê a dessincronização JSONB→JSON entre Postgres e SQLite, não distingue Index(unique=True) vs UniqueConstraint . Mas os drifts básicos entre models.py e o esquema real pega de forma confiável. Em um banco de dados de desenvolvimento local com lixo acumulado, este fluxo de trabalho não funciona — o drift é mascarado por objetos existentes. Cinco conclusões 1. Multi-tenant do primeiro commit via scoped_select helper e user.tenant_id — mesmo que haja apenas um tenant. Hardcoded config.TENANT_ID — esta é uma dívida técnica que dispara no segundo tenant e requer uma revisão de cada endpoint. 2. A proteção contra race-condition de reservas deve ser feita no nível do banco de dados via EXCLUDE USING gist + tsrange — mais barato e mais confiável que o application-level locking. Números reais: 12 solicitações concorrentes → 1×200, 11×409, p95 31.69ms. Não requer Redis ou coordenação distribuída. 3. Conformidade com 152-FZ — são campos e helpers , não uma marca de marketing. data_category enum em audit_logs com autoclassificador por entity_type , migração transparente PBKDF2 → argon2id via password_needs_rehash , separado patient_consents com versionamento scoped. 4. Verificação de integridade do banco de dados como um artefato operacional : sete categorias de anomalias que as restrições SQL não pegam. Execução contra um restore local do dump de produção antes de um grande lançamento — seguro de baixo custo. 5. Schema drift detection em CI — alembic upgrade head + alembic check em um PG limpo. Não funciona em um banco de dados de desenvolvimento com lixo acumulado: o drift é mascarado por objetos existentes. Tags: multi-tenant fastapi postgresql sqlalchemy exclude using gist argon2id pbkdf2 152-фз audit log b2b saas Hubs: Python PostgreSQL Segurança da Informação Programação

🛡️⚡

Pare de pesquisar. Comece a hackear.

O MundiX é seu copiloto de pentest com IA: comandos exatos, análise de outputs e próximo passo na kill chain — em segundos.

Testar grátis por 7 dias →

Sem cartão para começar · Planos a partir de R$49/mês

📤 Compartilhar & Baixar

🧰 Ferramentas recomendadas

Divulgação: alguns links são patrocinados. Podemos receber comissão se você comprar — sem custo extra para você. Só indicamos o que faz sentido para a comunidade.

Aprendendo Kali Linux: Teste de segurança, pentest e hacking ético

Aprendendo Kali Linux: Teste de segurança, pentest e hacking ético

Com centenas de ferramentas pré-instaladas, a distribuição Kali Linux facilita o trabalho de os profissionais de segurança começarem a fazer testes de segurança rapidamente. No entanto, com mais de 600 ferramentas em seu arsenal, o Kali Linux também pode ser desafiador. A nova edição deste prático livro abrange as atualizações nas ferramentas e inclui uma melhor abordagem da análise forense e da engenharia reversa. Ric Messier, autor, não fica apenas no teste de segurança, mas também faz uma abordagem sobre a execução de análise forense, incluindo a análise em disco e na memória, assim como alguma análise básica de malware. • Explore as diversas ferramentas disponíveis no Kali Linux • Entenda o valor do teste de segurança e examine os tipos de teste disponíveis • Aprenda os aspectos básicos do pentest em todo o ciclo de vida do ataque • Instale o Kali Linux em vários sistemas, tanto físicos quanto virtuais • Descubra como usar diferentes ferramentas destinadas à segurança • Estruture um teste de segurança baseado nas ferramentas do Kali Linux • Estenda as ferramentas do Kali para criar técnicas de ataque avançadas • Use o Kali Linux para ajudar a criar relatórios quando o teste terminar “A abordagem concisa, clara e baseada na experiência adotada por Ric Messier para a introdução do Kali Linux e dos testes de cibersegurança é incomparável. Este livro é uma leitura excelente e acessível para iniciantes e um recurso valioso para qualquer pessoa.” —Alexander Arlt, Consultor sênior de segurança, Google

Ver na Amazon
Gshield 2 em 1 Hub Extensor Conector USB-C + USB-A e Adaptador de Rede Ethernet LAN RJ45 com 3 Entradas USB 3.0 até 5 Gbps em Liga de Alumínio para Computador e Notebook, Cinza

Gshield 2 em 1 Hub Extensor Conector USB-C + USB-A e Adaptador de Rede Ethernet LAN RJ45 com 3 Entradas USB 3.0 até 5 Gbps em Liga de Alumínio para Computador e Notebook, Cinza

Compatível com portas USB-C e USB-A, ideal para ampliar a conectividade de dispositivos como MacBook Pro e outros com portas USB-C. Inclui um adaptador USB-A extra, proporcionando uma conexão Ethernet estável e veloz de até 1 Gbps, perfeita para filmes, jogos online e videoconferências. Oferece três portas USB 3.0 com velocidades de transferência de até 5 Gbps, permitindo conectar mouse, teclado, discos rígidos e outros periféricos. Fabricado em alumínio durável, garantindo longa vida útil e resistência ao uso diário. Design compacto e leve, ideal para viagens de negócios e uso diário, facilitando o transporte e armazenamento. Funciona com Windows 10/8.1/8, Mac OS e Chrome OS, oferecendo versatilidade incomparável para diversas necessidades de conectividade. Assegura uma conectividade estável e rápida, perfeita para tarefas exigentes como transferência de dados, streaming e mais.

Ver na Amazon
Hacking APIs: Breaking Web Application Programming Interfaces

Hacking APIs: Breaking Web Application Programming Interfaces

Hacking APIs is a crash course on web API security testing that will prepare you to penetration-test APIs, reap high rewards on bug bounty programs, and make your own APIs more secure. You'll learn how REST and GraphQL APIs work in the wild and set up a streamlined API testing lab with Burp Suite and Postman. Then you'll master tools useful for reconnaissance, endpoint analysis, and fuzzing, such as Kiterunner and OWASP Amass. Next, you'll learn to perform common attacks, like those targeting an API's authentication mechanisms and the injection vulnerabilities commonly found in web applications. You'll also learn techniques for bypassing protections against these attacks. In the book's nine guided labs, which target intentionally vulnerable APIs, you'll practice: Enumerating APIs users and endpoints using fuzzing techniques Using Postman to discover an excessive data exposure vulnerability Performing a JSON Web Token attack against an API authentication process Combining multiple API attack techniques to perform a NoSQL injection Attacking a GraphQL API to uncover a broken object level authorization vulnerability

Ver oferta
Gray Hat Hacking: The Ethical Hacker's Handbook, Sixth Edition

Gray Hat Hacking: The Ethical Hacker's Handbook, Sixth Edition

Up-to-date strategies for thwarting the latest, most insidious network attacks This fully updated, industry-standard security resource shows, step by step, how to fortify computer networks by learning and applying effective ethical hacking techniques. Based on curricula developed by the authors at major security conferences and colleges, the book features actionable planning and analysis methods as well as practical steps for identifying and combating both targeted and opportunistic attacks. Gray Hat Hacking: The Ethical Hacker's Handbook, Sixth Edition clearly explains the enemy's devious weapons, skills, and tactics and offers field-tested remedies, case studies, and testing labs. You will get complete coverage of Internet of Things, mobile, and Cloud security along with penetration testing, malware analysis, and reverse engineering techniques. State-of-the-art malware, ransomware, and system exploits are thoroughly explained. Fully revised content includes 7 new chapters covering the latest threats Includes proof-of-concept code stored on the GitHub repository Authors train attendees at major security conferences, including RSA, Black Hat, Defcon, and B-Sides

Ver na Amazon
Bloqueador USB de privacidade de porta USB para PC, notebook, bloco de laptop,

Bloqueador USB de privacidade de porta USB para PC, notebook, bloco de laptop,

Proteção de privacidade aprimorada: protege o link de transmissão de dados para evitar roubo de informações, fornecendo proteção de segurança robusta que protege a privacidade do usuário durante transferências de arquivos e garante uma conexão segura para interações de dispositivos sem preocupações em vários ambientes Uso a longo prazo: a camada protetora resistente ao desgaste, combinada com um corpo de metal resistente, oferece gerenciamento de calor confiável e qualidade duradoura durante o uso diário Entrega eficiente de energia: a tecnologia de chip inteligente garante a identificação automática dos requisitos de energia, fornecendo carregamento eficiente alinhando-se com vários protocolos de carregamento rápido para maior conveniência Proteção contra sobrecarga: evitando riscos de sobrecarga, este bloqueador de dados USB protege a vida útil da bateria e garante um desempenho estável, mantendo um fluxo estável de energia para melhorar a longevidade do dispositivo de forma eficaz Prático de transportar: com atenção à portabilidade, este bloqueador de dados USB oferece um design compacto que é leve e fácil de transportar, melhorando a conveniência do usuário e operação eficiente

Ver na Amazon

📩 Newsletter MundiX

Receba novidades de cibersegurança + um checklist de pentest grátis. Sem spam.

Ao assinar você concorda em receber e-mails. Cancele quando quiser.