antissrf 0.1.0

Rust implementation of Microsoft AntiSSRF
Documentation

AntiSSRF-rs

Crates.io Docs.rs License: MIT Rust

Rust implementation of Microsoft AntiSSRF — a security library for preventing Server-Side Request Forgery (SSRF) attacks.


Languages

Overview

AntiSSRF-rs is a Rust version of Microsoft's AntiSSRF library, designed to prevent Server-Side Request Forgery (SSRF) attacks by validating every outbound network request against a configurable security policy. It integrates seamlessly with reqwest and reqwest-middleware to provide DNS-level IP blocking, header validation, protocol enforcement, and redirect-chain re-validation.

Features

Feature Description
IP Blocking Block internal/sensitive IP addresses (localhost, private networks, cloud metadata services) using CIDR ranges
IPv6 Normalization Automatically maps IPv4 to IPv6-mapped addresses (::ffff:) for consistent CIDR matching
Header Enforcement Require specific headers (e.g., X-Forwarded-For) and deny dangerous headers
Protocol Control Reject plaintext HTTP to untrusted endpoints
Redirect Validation Re-validate every hop in a redirect chain against the same policy
Domain Validation Check URLs against trusted domains (with subdomain support) and Azure service endpoints
Immutable Policy Policy locks after first use to prevent runtime tampering
Optional Networking Core library has zero network dependencies; reqwest-integration feature adds HTTP client support

Quick Start

1. Add to Cargo.toml

[dependencies]
antissrf = "0.1"

Or with explicit feature control:

[dependencies]
# Core only (no HTTP client dependencies)
antissrf = { version = "0.1", default-features = false }

# Full reqwest integration (default)
antissrf = { version = "0.1", features = ["reqwest-integration"] }

2. Basic Policy

use antissrf::{AntiSSRFPolicy, PolicyConfigOptions};

// Block all known dangerous IPs (IMDS, WireServer, private networks, etc.)
let policy = AntiSSRFPolicy::new(PolicyConfigOptions::ExternalOnlyLatest);

3. With reqwest (DNS-level IP validation)

use antissrf::{AntiSSRFPolicy, PolicyConfigOptions};
use antissrf::network::reqwest_integration::AntiSSRFClientBuilder;

let policy = AntiSSRFPolicy::new(PolicyConfigOptions::ExternalOnlyLatest);
let client = AntiSSRFClientBuilder::new(policy)
    .timeout(std::time::Duration::from_secs(30))
    .build()
    .expect("Client should build");

4. With reqwest_middleware (header + protocol validation)

use antissrf::{AntiSSRFPolicy, PolicyConfigOptions};
use antissrf::network::reqwest_integration::AntiSSRFMiddleware;
use reqwest_middleware::ClientBuilder;

let policy = AntiSSRFPolicy::new(PolicyConfigOptions::ExternalOnlyLatest);
let middleware = AntiSSRFMiddleware::new(policy);

let client = ClientBuilder::new(reqwest::Client::new())
    .with(middleware)
    .build();

5. Fine-Grained Policy Configuration

use antissrf::{AntiSSRFPolicy, PolicyConfigOptions, AntiSSRFError};

let mut policy = AntiSSRFPolicy::new(PolicyConfigOptions::ExternalOnlyLatest);

// Allowlist takes precedence over denylist
policy.add_allowed_addresses(&["10.0.0.0/24"])?;

// Require specific headers
policy.add_required_headers(&["x-request-id"])?;

// Deny dangerous headers
policy.add_denied_headers(&["x-forwarded-host", "x-http-host-override"])?;

// Block plaintext HTTP
policy.set_allow_plaintext_http(false)?;

// Validate an outgoing request
let mut headers = vec![
    ("x-request-id".to_string(), "abc123".to_string()),
];
let allowed = policy.validate_request("https:", &mut headers)?;
assert!(allowed);

6. Domain Validation

use antissrf::uri_validator;

// Check if URL is in a trusted domain (supports subdomains)
assert!(uri_validator::in_domain("https://api.example.com/path", &["example.com"]));

// Azure Key Vault domain validation
assert!(uri_validator::in_azure_key_vault_domain("https://myvault.vault.azure.net"));

// Rejects hostnames containing '--' (Azure naming restriction)
assert!(!uri_validator::in_azure_key_vault_domain("https://my--vault.vault.azure.net"));

PolicyConfigOptions

Option Behavior
None No restrictions — allow all requests
InternalOnly Block external IPs (deny all unspecified)
ExternalOnlyV1 Block IMDS + WireServer + special ranges (v1 blocklist)
ExternalOnlyLatest Same as V1 — alias for the latest recommended blocklist

Modules

Module Purpose
error Error types (AntiSSRFError)
cidr CIDR block parsing and IP containment
ip_address_ranges Predefined special IP ranges (IMDS, WireServer, loopback, etc.)
domains Azure service domain lists (Key Vault, Storage)
uri_validator URL and domain validation utilities
policy Policy configuration and runtime enforcement
network reqwest integration (resolver + middleware + client builder)

Running Tests

# Core tests (no network dependencies)
cargo test --lib

# With reqwest integration (default features)
cargo test --features reqwest-integration

# All tests with output
cargo test --features reqwest-integration -- --nocapture

# Documentation tests
cargo test --doc

Security Design

  • Evaluation Order: Allowlist → deny_all_unspecified_ips → Denylist. An allowlisted IP is always permitted, even if it also appears in a denylist.
  • IPv6 Normalization: All IPv4 addresses are mapped to ::ffff:<ipv4> before CIDR checks. IPv4 /24 becomes IPv6-mapped /120 (add 96 to prefix length).
  • Case-Insensitive Headers: Header names are matched case-insensitively; header values are matched case-sensitively.
  • Edit Lock: Once a policy is used for validation, it becomes immutable to prevent runtime tampering.
  • Redirect Re-Validation: Every redirect hop is re-validated against the same policy, preventing open-redirect bypasses.

License

MIT — See LICENSE for details.

References