Os 10 riscos de segurança mais críticos em sistemas de machine learning e como mitigá-los.
O OWASP Machine Learning Security Top 10 identifica os riscos de segurança mais significativos específicos de sistemas de machine learning. Diferentemente de software tradicional, sistemas ML são vulneráveis a ataques únicos que visam dados de treinamento, componentes internos do modelo e pipelines de inferência. Este guia abrange ataques adversariais, envenenamento de dados, roubo de modelos, riscos na cadeia de suprimentos e mais Ecom exemplos práticos de código Python.
Ataques de manipulação de entrada (ataques adversariais) criam entradas especialmente projetadas para fazer com que modelos ML façam previsões incorretas. Pequenas perturbações, muitas vezes imperceptíveis, em imagens, texto ou outras entradas podem enganar classificadores, burlar sistemas de detecção e evadir filtros de conteúdo. Este é o vetor de ataque mais conhecido específico de ML.
Exemplos adversariais podem burlar sistemas ML críticos para segurança: percepção de veículos autônomos, detecção de malware, detecção de fraude e moderação de conteúdo. Um atacante pode fazer com que uma placa de pare seja classificada como uma placa de limite de velocidade, ou fazer malware parecer benigno para um antivírus baseado em ML.
import numpy as np from tensorflow import keras # Model with no adversarial robustness model = keras.models.load_model("classifier.h5") def predict(image): # Direct prediction Eno input validation or preprocessing result = model.predict(np.expand_dims(image, axis=0)) return np.argmax(result) # No confidence threshold check # No input bounds validation # Vulnerable to FGSM, PGD, C&W attacks
import numpy as np from tensorflow import keras from art.defences.preprocessor import SpatialSmoothing from art.defences.detector.evasion import BinaryInputDetector # Load adversarially trained model model = keras.models.load_model("classifier_robust.h5") # Input preprocessing to remove perturbations smoother = SpatialSmoothing(window_size=3) detector = BinaryInputDetector(model) def predict_secure(image): # Validate input bounds if image.min() < 0 or image.max() > 1: raise ValueError("Input out of expected range") # Detect adversarial input if detector.detect(image): raise ValueError("Adversarial input detected") # Apply spatial smoothing defense cleaned = smoother(image)[0] result = model.predict(np.expand_dims(cleaned, axis=0)) # Reject low-confidence predictions confidence = np.max(result) if confidence < 0.85: return {"label": "uncertain", "confidence": confidence} return {"label": np.argmax(result), "confidence": confidence}
Ataques de envenenamento de dados injetam amostras maliciosas em conjuntos de dados de treinamento para corromper o comportamento aprendido do modelo. Atacantes podem introduzir backdoors (padrões de gatilho que causam classificações errôneas específicas), deslocar limites de decisão ou degradar a precisão geral do modelo. Isso é especialmente perigoso quando dados de treinamento vêm da internet ou conteúdo gerado por usuários.
Um modelo envenenado pode se comportar normalmente em entradas limpas, mas classificar incorretamente quando um padrão de gatilho específico está presente. Por exemplo, um classificador de malware com backdoor poderia aprovar qualquer amostra de malware contendo uma sequência de bytes específica. O ataque é furtivo porque a precisão do modelo em dados limpos permanece alta.
import pandas as pd from sklearn.ensemble import RandomForestClassifier # Training on unvalidated, crowdsourced data data = pd.read_csv("user_submitted_data.csv") # No validation! # No outlier detection or data quality checks X = data.drop("label", axis=1) y = data["label"] model = RandomForestClassifier() model.fit(X, y) # Training directly on untrusted data! # No comparison against clean baseline # No data provenance tracking
import pandas as pd import numpy as np from sklearn.ensemble import RandomForestClassifier, IsolationForest from sklearn.model_selection import cross_val_score # Load data with provenance tracking data = pd.read_csv("training_data.csv") data_hash = hashlib.sha256(data.to_csv().encode()).hexdigest() log.info(f"Training data hash: {data_hash}") X = data.drop("label", axis=1) y = data["label"] # Detect and remove anomalous samples iso_forest = IsolationForest(contamination=0.05, random_state=42) outlier_mask = iso_forest.fit_predict(X) == 1 X_clean, y_clean = X[outlier_mask], y[outlier_mask] log.info(f"Removed {(~outlier_mask).sum()} outliers from {len(X)} samples") # Train and validate against baseline model = RandomForestClassifier(random_state=42) scores = cross_val_score(model, X_clean, y_clean, cv=5) if scores.mean() < BASELINE_ACCURACY - 0.05: raise ValueError("Model accuracy dropped Epossible data poisoning") model.fit(X_clean, y_clean)
Ataques de inversão de modelo reconstroem dados sensíveis de treinamento consultando o modelo e analisando suas saídas. Um atacante pode recuperar informações privadas como rostos, registros médicos ou dados pessoais usados durante o treinamento. Isso é particularmente preocupante para modelos treinados em conjuntos de dados sensíveis (saúde, biometria, dados financeiros).
Inversão de modelo pode violar regulamentações de privacidade de dados (GDPR, HIPAA) ao expor informações pessoalmente identificáveis de dados de treinamento. Um atacante com acesso à API de um modelo de reconhecimento facial poderia reconstruir rostos de indivíduos no conjunto de treinamento.
from flask import Flask, request, jsonify app = Flask(__name__) model = load_model("face_classifier.h5") @app.route("/predict", methods=["POST"]) def predict(): image = request.files["image"] result = model.predict(preprocess(image)) # Returns full probability vector Eenables model inversion! return jsonify({ "probabilities": result.tolist(), # All class probabilities! "prediction": int(np.argmax(result)), "confidence": float(np.max(result)) }) # No rate limiting, no query logging # Unlimited API access for gradient estimation
from flask import Flask, request, jsonify from flask_limiter import Limiter import numpy as np app = Flask(__name__) limiter = Limiter(app, default_limits=["100/hour"]) model = load_model("face_classifier_dp.h5") # Trained with DP @app.route("/predict", methods=["POST"]) @limiter.limit("100/hour") def predict(): image = request.files["image"] result = model.predict(preprocess(image)) # Return only top-1 prediction Eno probability vector prediction = int(np.argmax(result)) log_query(request.remote_addr, prediction) # Audit logging return jsonify({ "prediction": prediction # No probabilities, no confidence scores })
Ataques de inferência de pertencimento determinam se um ponto de dados específico foi usado no conjunto de treinamento do modelo. Ao analisar as pontuações de confiança e o comportamento do modelo em entradas conhecidas vs. desconhecidas, atacantes podem inferir informações privadas de pertencimento. Esta é uma ameaça significativa à privacidade para modelos treinados em dados sensíveis.
Inferência de pertencimento pode revelar que os dados de um indivíduo específico foram usados para treinamento Epor exemplo, confirmar que o registro de um paciente estava em um conjunto de dados clínicos, ou que o rosto de uma pessoa foi usado para treinamento de vigilância. Isso viola expectativas de privacidade e potencialmente regulamentações como GDPR.
from sklearn.neural_network import MLPClassifier # Overfitted model Ememorizes training data model = MLPClassifier( hidden_layer_sizes=(512, 512, 256), # Over-parameterized! max_iter=1000, # No regularization # No early stopping ) model.fit(X_train, y_train) # Model memorizes training data ↁEmembership inference possible # Training accuracy: 99.9% vs Test accuracy: 82% # This gap indicates overfitting = information leakage def predict_with_confidence(x): proba = model.predict_proba([x])[0] return {"probabilities": proba.tolist()} # Leaks membership info!
from sklearn.neural_network import MLPClassifier import numpy as np # Regularized model with early stopping to reduce overfitting model = MLPClassifier( hidden_layer_sizes=(128, 64), max_iter=500, alpha=0.01, # L2 regularization early_stopping=True, # Prevents memorization validation_fraction=0.15, ) model.fit(X_train, y_train) # Verify train/test gap is small (low overfitting) train_acc = model.score(X_train, y_train) test_acc = model.score(X_test, y_test) assert train_acc - test_acc < 0.05, "Overfitting detected!" def predict_secure(x): pred = model.predict([x])[0] return {"prediction": int(pred)} # Label only, no probabilities
Ataques de roubo de modelo (extração de modelo) criam uma cópia funcional de um modelo ML proprietário consultando-o sistematicamente e treinando um modelo substituto nos pares entrada-saída. O modelo roubado pode então ser usado para encontrar exemplos adversariais, competir comercialmente ou fazer engenharia reversa dos dados de treinamento do modelo.
Um modelo roubado representa perda de propriedade intelectual e vantagem competitiva. O modelo extraído pode ser usado offline para criar ataques adversariais ou entender limites de decisão. Milhões de dólares de investimento em treinamento podem ser replicados com milhares de consultas à API.
from flask import Flask, request, jsonify app = Flask(__name__) model = load_proprietary_model() @app.route("/predict", methods=["POST"]) def predict(): data = request.json["features"] result = model.predict_proba([data])[0] # Returns full probability distribution return jsonify({ "probabilities": result.tolist(), "prediction": int(np.argmax(result)) }) # No rate limiting Eunlimited queries # No anomaly detection on query patterns # Attacker can extract model with ~10K queries
from flask import Flask, request, jsonify from flask_limiter import Limiter import numpy as np app = Flask(__name__) limiter = Limiter(app, default_limits=["50/hour"]) # Watermarked model for theft detection model = load_watermarked_model() query_monitor = QueryPatternDetector() @app.route("/predict", methods=["POST"]) @limiter.limit("50/hour") def predict(): data = request.json["features"] api_key = request.headers.get("X-API-Key") # Detect extraction patterns (uniform sampling, grid queries) if query_monitor.is_suspicious(api_key, data): log_alert(f"Possible extraction: {api_key}") return jsonify({"error": "rate limited"}), 429 result = model.predict([data])[0] return jsonify({ "prediction": int(result) # Label only, no probabilities })
Ataques à cadeia de suprimentos de IA visam o pipeline de desenvolvimento ML: modelos pré-treinados de repositórios de modelos, conjuntos de dados de terceiros, frameworks ML e dependências. Modelos maliciosos podem conter backdoors ocultos, e bibliotecas comprometidas podem injetar vulnerabilidades. Os formatos de serialização usados por frameworks ML (Pickle, SavedModel) podem executar código arbitrário ao carregar.
Carregar um arquivo de modelo malicioso pode executar código arbitrário (ataques de desserialização Pickle). Modelos pré-treinados de fontes não confiáveis podem conter backdoors. Bibliotecas ML comprometidas afetam todos os usuários downstream. A cadeia de suprimentos ML tem menos controles de segurança do que cadeias de suprimentos de software tradicionais.
import pickle import torch # Loading untrusted model Earbitrary code execution! with open("model_from_internet.pkl", "rb") as f: model = pickle.load(f) # DANGEROUS: can execute any code! # Loading unverified PyTorch model model = torch.load("untrusted_model.pt") # Uses pickle internally! # Using unvetted model from public hub from transformers import AutoModel model = AutoModel.from_pretrained("random-user/suspicious-model") # No hash verification, no security scan
import torch import hashlib from safetensors.torch import load_file # Use SafeTensors Eno arbitrary code execution model_state = load_file("model.safetensors") # Safe format! model = MyModel() model.load_state_dict(model_state) # Verify model hash before loading EXPECTED_HASH = "sha256:a1b2c3d4..." with open("model.safetensors", "rb") as f: actual_hash = "sha256:" + hashlib.sha256(f.read()).hexdigest() assert actual_hash == EXPECTED_HASH, "Model integrity check failed!" # Use trusted models from verified organizations from transformers import AutoModel model = AutoModel.from_pretrained( "google/bert-base-uncased", # Verified organization revision="a265f77", # Pin to specific commit )
Ataques de transfer learning exploram a prática comum de ajustar modelos pré-treinados. Backdoors incorporados no modelo base persistem através do ajuste fino e permanecem ativos no modelo downstream. Um atacante que publica um modelo pré-treinado popular pode comprometer todas as aplicações que o usam como fundação.
Backdoors em modelos pré-treinados sobrevivem ao ajuste fino porque estão incorporados em camadas profundas que são frequentemente congeladas durante o transfer learning. Um único modelo fundacional comprometido pode afetar milhares de aplicações downstream. O ataque é escalável e difícil de detectar.
from transformers import AutoModelForSequenceClassification # Fine-tuning an unvetted pre-trained model model = AutoModelForSequenceClassification.from_pretrained( "unknown-user/bert-finetuned-sentiment", # Untrusted source! num_labels=2 ) # Freezing base layers Epreserves any hidden backdoor for param in model.base_model.parameters(): param.requires_grad = False # Backdoor in frozen layers persists! # Fine-tune only the classification head trainer.train() # Backdoor remains undetected
from transformers import AutoModelForSequenceClassification from neural_cleanse import BackdoorDetector # Use only verified, trusted base models model = AutoModelForSequenceClassification.from_pretrained( "google/bert-base-uncased", # Trusted source num_labels=2, revision="main", ) # Scan pre-trained model for backdoors before fine-tuning detector = BackdoorDetector(model) if detector.scan(): raise SecurityError("Potential backdoor detected in base model") # Fine-tune ALL layers (not just head) to overwrite potential backdoors for param in model.parameters(): param.requires_grad = True # Train all layers # Validate with clean test set + trigger test set trainer.train() evaluate_for_backdoors(model, trigger_test_set)
Desvio de modelo ocorre quando a distribuição de dados em produção difere significativamente da distribuição de dados de treinamento (desvio treinamento-serviço). Isso pode acontecer naturalmente ao longo do tempo (deriva de dados) ou ser intencionalmente causado por atacantes que manipulam a distribuição de entrada de produção para degradar o desempenho do modelo ou enviesar previsões.
Desvio de modelo causa falhas silenciosas onde o modelo produz previsões incorretas mas confiantes. Em sistemas financeiros, atacantes podem explorar desvio para burlar detecção de fraude. Em sistemas de recomendação, desvio pode ser intencionalmente induzido para promover conteúdo ou produtos específicos.
import joblib # Deploy model with no drift monitoring model = joblib.load("model_trained_2023.pkl") def predict(features): # No check if input distribution has changed # No feature validation against training schema return model.predict([features])[0] # Model may be months/years old # No monitoring of prediction distribution # Silent degradation goes undetected
import joblib import numpy as np from scipy import stats from evidently import ColumnDriftMetric model = joblib.load("model.pkl") training_stats = joblib.load("training_stats.pkl") def predict_with_monitoring(features): # Validate feature schema and ranges for i, (val, stat) in enumerate(zip(features, training_stats)): z_score = abs((val - stat["mean"]) / stat["std"]) if z_score > 5: log.warning(f"Feature {i} out of distribution: z={z_score:.1f}") prediction = model.predict([features])[0] # Log prediction distribution for drift monitoring metrics_collector.log(features, prediction) # Periodic drift detection (run by monitoring job) # drift_report = ColumnDriftMetric().calculate(reference, current) # Alert if drift detected ↁEtrigger retraining return prediction
Ataques de integridade de saída adulteram previsões do modelo depois que elas deixam o modelo mas antes de chegarem à aplicação consumidora. Isso inclui ataques man-in-the-middle em APIs de previsão, manipulação de infraestrutura de servir modelo e adulteração de previsões em cache. O ataque visa o pipeline de inferência em vez do modelo em si.
Previsões adulteradas podem causar decisões incorretas em sistemas downstream: aprovar transações fraudulentas, diagnosticar incorretamente condições médicas ou sobrescrever sistemas de segurança. Como o modelo em si não está comprometido, monitoramento padrão do modelo não detectará o ataque.
import requests # Consuming model predictions over unencrypted HTTP def get_prediction(features): response = requests.post( "http://ml-service/predict", # HTTP, not HTTPS! json={"features": features} ) result = response.json() # No integrity verification of the response # No validation of prediction format return result["prediction"] # Could be tampered!
import requests import hmac import hashlib def get_prediction(features): response = requests.post( "https://ml-service/predict", # HTTPS (TLS) json={"features": features}, headers={"Authorization": f"Bearer {API_TOKEN}"}, verify=True # Verify TLS certificate ) result = response.json() # Verify response integrity with HMAC signature signature = response.headers.get("X-Signature") expected = hmac.new( SHARED_SECRET, str(result).encode(), hashlib.sha256 ).hexdigest() if not hmac.compare_digest(signature, expected): raise IntegrityError("Response signature mismatch!") # Validate prediction is within expected range pred = result["prediction"] if pred not in VALID_LABELS: raise ValueError(f"Unexpected prediction: {pred}") return pred
Envenenamento de modelo modifica diretamente os pesos, parâmetros ou arquitetura do modelo treinado para injetar backdoors ou alterar comportamento. Diferentemente do envenenamento de dados (que corrompe dados de treinamento), envenenamento de modelo visa o artefato do modelo em si Eatravés de repositórios de modelos comprometidos, ameaças internas ou ataques à cadeia de suprimentos no pipeline de armazenamento e implantação do modelo.
Um modelo diretamente envenenado pode conter backdoors altamente direcionados que são virtualmente indetectáveis através de testes padrão. O atacante tem controle preciso sobre o comportamento do modelo em entradas de gatilho. Se o registro de modelos ou pipeline de implantação estiver comprometido, cada implantação usa o modelo envenenado.
import mlflow # Loading model from registry with no integrity checks model_uri = "models:/fraud-detector/Production" model = mlflow.pyfunc.load_model(model_uri) # No hash verification # No signature validation # No comparison with expected model metrics # Model registry has weak access controls # Anyone with push access can replace the model predictions = model.predict(new_data)
import mlflow import hashlib from sigstore.verify import Verifier # Verify model signature before loading model_uri = "models:/fraud-detector/Production" model_path = mlflow.artifacts.download_artifacts(model_uri) # Cryptographic signature verification verifier = Verifier.production() verifier.verify( model_path, expected_identity="ml-team@company.com" ) # Verify model hash against approved registry model_hash = hash_directory(model_path) approved_hash = get_approved_hash("fraud-detector", "Production") assert model_hash == approved_hash, "Model integrity check failed!" # Validate model metrics on reference dataset before serving model = mlflow.pyfunc.load_model(model_path) ref_score = evaluate(model, reference_dataset) assert ref_score >= MINIMUM_ACCURACY, "Model quality below threshold" predictions = model.predict(new_data)
| ID | Vulnerabilidade | Severidade | Mitigação Chave |
|---|---|---|---|
| ML01 | Ataque de Manipulação de Entrada | Critical | Treinamento adversarial, validação de entrada, limites de confiança |
| ML02 | Ataque de Envenenamento de Dados | Critical | Detecção de outliers, proveniência de dados, comparação com baseline |
| ML03 | Ataque de Inversão de Modelo | High | Privacidade Diferencial, saída mínima, limitação de taxa |
| ML04 | Ataque de Inferência de Pertencimento | High | Regularização, treinamento DP, sem exposição de probabilidade |
| ML05 | Roubo de Modelo | Critical | Limitação de taxa, marca d'água, detecção de padrão de consulta |
| ML06 | Ataques à Cadeia de Suprimentos de IA | Critical | SafeTensors, verificação de hash, apenas fontes confiáveis |
| ML07 | Ataque de Transfer Learning | High | Modelos base confiáveis, escaneamento de backdoor, ajuste completo |
| ML08 | Desvio de Modelo | Medium | Monitoramento de deriva, validação de entrada, retreinamento automático |
| ML09 | Ataque de Integridade de Saída | High | TLS/mTLS, assinatura de resposta, validação de saída |
| ML10 | Envenenamento de Modelo | Critical | Assinatura de modelo, controle de acesso a registro, validação de métricas |