Skip to content
Fraud Prevention

How to Prevent Cyber Attacks Using IP Geolocation

13 min readGeoIPHub Team

Most provider overviews list "9 ways to use IP geolocation for security." They describe the mechanisms correctly but stop there, with no code, no thresholds, and no implementation guidance. This guide goes further: every technique includes the API call, the response fields that matter, and how to act on them. If you want the concepts first, what IP intelligence covers beyond geolocation lays out each data layer.

What IP Intelligence Returns

Every technique below draws on one or more fields from a single IP lookup. Here is a real response for 185.220.101.47, a Tor exit node, trimmed to the fields this guide uses:

GeoIPHub API
curl -H "x-api-key: YOUR_API_KEY" \ https://api.geoiphub.com/v1/lookup/185.220.101.47
GeoIPHub API
{ "ip": "185.220.101.47", "asn": { "asn": 60729, "org": "TORSERVERS-NET - Stiftung Erneuerbare Freiheit", "asn_type": "hosting", "connection_type": "datacenter" }, "geo": { "country_code": "DE", "region": "Hamburg", "city": "Hamburg (Hamburg-Nord)", "latitude": 53.5735, "longitude": 10.0548, "timezone": "Europe/Berlin" }, "detection": { "is_vpn": false, "is_proxy": false, "is_tor": true, "is_hosting": true, "is_anonymous": true }, "threat": { "is_abusive": false, "is_scanner": false, "is_botnet": false, "threat_types": ["tor"], "dnsbl_sources": [] }, "scoring": { "fraud_score": 79, "confidence": 0.6736666666666667, "recommended_action": "block", "detection_methods": ["tor_exit", "datacenter_ip", "rdns_tor"] }, "meta": { "last_scanned": "2026-09-29T12:23:34.000Z" } }

One request. The groups the techniques below read from are geo, asn, detection, threat and scoring. The code samples assume a small helper, geoiphub_lookup(ip), that calls this endpoint and returns the parsed JSON.

Technique 1: Block Known Malicious IPs at the Perimeter

The cheapest defense: reject requests from IPs with documented abuse or anonymizer evidence before they touch your application. The threat group carries the abuse flags and the matched threat_types, and the scoring group rolls everything into a recommended action.

GeoIPHub API
def check_ip_at_entry(ip: str) -> dict: data = geoiphub_lookup(ip) threat, scoring = data["threat"], data["scoring"] # Hard block: listed abuse source, scanner or botnet infrastructure if threat["is_abusive"] or threat["is_scanner"] or threat["is_botnet"]: return {"action": "block", "reason": "known_abuse_source"} # Hard block: known Tor exit node (in transaction flows) if data["detection"]["is_tor"]: return {"action": "block", "reason": "tor_exit_node"} return {"action": "continue", "fraud_score": scoring["fraud_score"]}

Calibrate by flow. A password reset form can act on recommended_action: "step_up", while a public content endpoint might only act on "block". The scoring.confidence field (0.0 to 1.0) tells you how much evidence sits behind the score, so reserve hard blocks for verdicts backed by strong evidence.

Technique 2: Detect and Restrict VPN and Proxy Traffic

Anonymization services hide the user's real location and identity. Commercial VPNs have millions of legitimate users, so blocking all VPN traffic is too broad for most products. Proxies and Tor exits in transaction flows have almost no legitimate use case.

GeoIPHub API
def anonymization_response(ip: str, flow: str) -> str: det = geoiphub_lookup(ip)["detection"] # Tor exits: block in all sensitive flows if det["is_tor"]: return "block" if flow in ["checkout", "login", "signup"] else "challenge" # SOCKS/HTTP proxies: almost always abuse tooling if det["is_proxy"]: return "block" # Commercial VPN: challenge in sensitive flows, allow in low-risk if det["is_vpn"]: return "challenge" if flow in ["checkout", "payment"] else "allow_log" return "allow"

The detection mechanism behind each flag:

  • detection.is_vpn: IP matched against VPN providers' own published server lists (NordVPN, Mullvad, Surfshark and others) and active OpenVPN/WireGuard/IPsec handshake probing
  • detection.is_proxy: Port probing on SOCKS and HTTP proxy greeting sequences
  • detection.is_tor: Match against the official Tor Project exit list
  • detection.is_residential_proxy: A coarse, ASN-based inference only, not a direct observation of proxy-network membership. Treat it as a hint, never as the sole reason to block.

Technique 3: Enforce Geographic Restrictions

Compliance requirements, licensing agreements, and sanctions programs sometimes require hard geo-restrictions that block access from specific countries or regions. The geo.country_code field supports this, but the check must also catch users bypassing restrictions with VPNs.

GeoIPHub API
BLOCKED_COUNTRIES = {"KP", "IR", "CU", "SY"} # sanctions compliance example RESTRICTED_FLOWS = {"checkout", "download", "api_access"} def check_geo_compliance(ip: str, flow: str) -> dict: data = geoiphub_lookup(ip) # Country-level block if data["geo"]["country_code"] in BLOCKED_COUNTRIES and flow in RESTRICTED_FLOWS: return {"action": "block", "reason": "geo_compliance"} # VPN bypass attempt: the apparent location may not be real if data["detection"]["is_anonymous"] and flow in RESTRICTED_FLOWS: # You cannot trust the geolocation when an anonymizer is active return {"action": "block", "reason": "geo_verification_impossible"} return {"action": "allow"}

The critical point most overviews omit: VPN detection is required for geo-restriction enforcement to be meaningful. If you block country_code: "IR" but allow is_vpn: true requests, users in restricted jurisdictions simply connect through a VPN server in Germany and your block fails. Effective geo-compliance requires both fields together.

Technique 4: Flag Impossible Travel on Account Logins

Impossible travel is one of the most reliable signals for account takeover. A human cannot log in from London and Singapore within 30 minutes, so one of those sessions is from stolen credentials or a compromised device.

GeoIPHub API
import math from datetime import datetime, timedelta def haversine_km(lat1, lon1, lat2, lon2) -> float: R = 6371 dlat = math.radians(lat2 - lat1) dlon = math.radians(lon2 - lon1) a = math.sin(dlat/2)**2 + math.cos(math.radians(lat1)) * \ math.cos(math.radians(lat2)) * math.sin(dlon/2)**2 return R * 2 * math.asin(math.sqrt(a)) def check_impossible_travel(user_id: str, current_ip: str) -> dict: current = geoiphub_lookup(current_ip)["geo"] previous = get_last_login(user_id) # {ip, latitude, longitude, timestamp} if not previous: return {"action": "allow"} distance_km = haversine_km( previous["latitude"], previous["longitude"], current["latitude"], current["longitude"] ) hours_elapsed = (datetime.now() - previous["timestamp"]).total_seconds() / 3600 required_hours = distance_km / 900 # ~commercial aircraft speed if distance_km > 500 and hours_elapsed < required_hours: return { "action": "block_session_flag_account", "reason": "impossible_travel", "distance_km": round(distance_km), "hours_elapsed": round(hours_elapsed, 1), "hours_required": round(required_hours, 1) } return {"action": "allow"}

Two calibration notes: First, VPN users will trigger impossible travel by switching server locations, so check detection.is_vpn before logging the location as ground truth, because a VPN location is not a real location. Second, mobile users on CGNAT share IPs, so geolocation precision at city level is lower. Set a minimum distance threshold of at least 200 km before flagging to avoid false positives from CGNAT-induced location drift.

Technique 5: Block Automated Scanning and Scraping

Credential stuffing attacks, vulnerability scans, content scrapers, and price comparison bots overwhelmingly originate from cloud and datacenter IPs. Real people mostly use residential ISPs or mobile networks, so a checkout from AS16509 (Amazon Web Services) deserves a closer look. It isn't proof of fraud on its own: AI shopping agents acting for real buyers also egress from cloud ranges. Treat hosting as one weighted input and add friction, rather than hard-blocking on it alone.

GeoIPHub API
def is_likely_automated(ip: str, flow: str) -> bool: data = geoiphub_lookup(ip) det, threat, scoring = data["detection"], data["threat"], data["scoring"] # Verified search and AI crawlers are automated but expected if threat["crawler"]["verified"]: return False # Hosting / cloud IPs at consumer flows: likely automated, so add friction, # but don't hard-block on this signal alone if det["is_hosting"] and flow in ["login", "checkout", "signup"]: return True # Known scanner or botnet infrastructure if threat["is_scanner"] or threat["is_botnet"]: return True # Block-band score with hosting context if scoring["fraud_score"] > 75 and data["asn"]["asn_type"] == "hosting": return True return False

The asn.asn_type values that indicate infrastructure rather than real users:

  • hosting: cloud, dedicated server and VPS providers (AWS, Google Cloud, DigitalOcean and similar)
  • cdn: Cloudflare, Akamai, Fastly (edge nodes, not users)
  • vpn: ASNs with documented VPN server history

The asn_type: "isp" or asn_type: "mobile" types are baseline legitimate: that is where real people connect from. Scrapers that rent those home and mobile IPs need log-level checks, which our guide on how to tell if your site is being scraped walks through.

Technique 6: Rate Limit and Throttle by Network Context

Rate limiting is more effective when calibrated to the infrastructure type behind the IP. A single residential IP can be a CGNAT address shared by hundreds of users, so throttling it aggressively blocks real people. A datacenter IP is almost certainly one automated client, so throttle it severely.

GeoIPHub API
RATE_LIMITS = { "isp": {"requests_per_minute": 60, "action_on_exceed": "delay"}, "mobile": {"requests_per_minute": 120, "action_on_exceed": "delay"}, # CGNAT = many users "hosting": {"requests_per_minute": 5, "action_on_exceed": "block"}, "vpn": {"requests_per_minute": 20, "action_on_exceed": "challenge"}, "cdn": {"requests_per_minute": 100, "action_on_exceed": "delay"}, # could be your own edge } def get_rate_limit(ip: str) -> dict: data = geoiphub_lookup(ip) asn_type = data["asn"].get("asn_type", "isp") limits = RATE_LIMITS.get(asn_type, RATE_LIMITS["isp"]) # Escalate if the score is in the block band regardless of ASN type if data["scoring"]["recommended_action"] == "block": limits = {"requests_per_minute": 3, "action_on_exceed": "block"} return limits

Technique 7: Detect High-Risk Countries at Checkout

Country-level fraud risk varies significantly by product and market. For payment fraud specifically, certain country-to-billing-address mismatches are a high-signal pattern: a card with a UK billing address used from an IP geolocated to a high-fraud-volume region.

GeoIPHub API
def assess_checkout_geo_risk(ip: str, billing_country: str) -> dict: data = geoiphub_lookup(ip) det = data["detection"] ip_country = data["geo"]["country_code"] # An anonymizer blocks the check: you cannot trust the apparent country if det["is_vpn"] or det["is_proxy"] or det["is_tor"] or det["is_relay"]: return { "risk_level": "high", "reason": "country_unverifiable_due_to_anonymizer", "action": "require_3ds" } # Country mismatch between IP and billing address if ip_country != billing_country: return { "risk_level": "elevated", "reason": f"ip_country_{ip_country}_billing_{billing_country}", "action": "require_3ds" } return {"risk_level": "standard", "action": "allow"}

Do not build a hardcoded block list of "risky countries" and maintain it manually. Use the IP's risk signals (anonymization status, abuse flags, ASN type) to detect the infrastructure behind attacks rather than the geography it appears to come from. Sophisticated attackers deliberately route through clean-looking IPs in low-risk country geolocation pools.

Technique 8: Filter Invalid Traffic Before It Reaches Analytics

Automated bots, crawlers, and scrapers contaminate your analytics data and, more damagingly, your paid ad conversion signals. Filtering at the IP intelligence layer before events register in GA4 or your Smart Bidding model protects signal quality.

GeoIPHub API
def should_record_session(ip: str) -> bool: data = geoiphub_lookup(ip) det, threat, scoring = data["detection"], data["threat"], data["scoring"] # Verified crawlers (Googlebot, Bingbot): exclude from analytics but don't block if threat["crawler"]["verified"]: return False # Hosting IPs with elevated scores are not users if det["is_hosting"] and scoring["fraud_score"] > 50: return False # Anonymizers with no conversion value to PPC if det["is_tor"] or det["is_proxy"]: return False # Block-band scores: likely automated regardless of IP type if scoring["recommended_action"] == "block": return False return True

For paid traffic specifically: any session from a datacenter or known bot IP that converts triggers an invalid conversion event in Google Ads. Those corrupt the Smart Bidding model because the model learns that "sessions from [signal cluster]" don't convert, then under-bids for real buyers who share some of those signals. Paid traffic has its own playbook, and it starts by abandoning the IP exclusion list. See how to detect click fraud by IP address.

Decision Matrix: Which IP Signal Prevents Which Attack

What IP Geolocation Cannot Catch Alone

IP geolocation is a first-pass filter. It misses:

Residential proxies with clean reputations. An IP that was added to a proxy pool yesterday has no abuse history and passes blocklist checks. Detection requires behavioral signals that IP intelligence alone cannot supply: device fingerprint anomalies, session timing patterns, interaction rate.

Compromised human accounts. If an attacker has valid credentials and uses a clean residential IP in the same country as the victim, there is nothing in the IP data to flag. Behavioral signals (typing speed, navigation patterns, purchase history divergence) are needed.

Sophisticated targeted attacks. A targeted attacker who researches your defenses will use a clean residential IP in the same city as the victim. They pass every IP-level check. Email verification and device binding are the defenses here.

The correct model: IP intelligence filters the volume of automated and low-sophistication attacks at near-zero cost per request, so that more expensive checks (device fingerprinting, behavioral analysis, manual review) can focus on the remainder. For how that filter maps onto specific crime categories such as account takeover, card testing and fake accounts, see the role of IP intelligence against cybercrime.

Implementation Notes

Cache aggressively. IP data changes infrequently within a single session. Cache per IP for the duration of the session (15–30 minutes) with a short TTL (1 hour for security-critical data, 24 hours for basic geo-fields). One lookup per IP per session is the practical cost model.

Log the full response, not just the verdict. When a block fires, you want to know which signal triggered it. Store the scoring.detection_methods array and the raw scoring.fraud_score with every decision. That is how you identify false positives and tune thresholds.

Tune thresholds per flow, not per site. A password reset flow deserves a lower block threshold than a blog read. Define thresholds in configuration, not in code, so your security team can adjust without a deployment.

GeoIPHub API
FLOW_THRESHOLDS = { "checkout": {"block_above": 75, "challenge_above": 50}, "login": {"block_above": 80, "challenge_above": 55}, "signup": {"block_above": 85, "challenge_above": 60}, "api_read": {"block_above": 90, "challenge_above": 75}, }

The GeoIPHub free tier covers 1,500 lookups per day with all fields returned, including infrastructure type, anonymization detection, and risk score. No separate subscription for "threat data" or "proxy detection." The full response is one endpoint.

GeoIPHub API
# Test any IP free: anonymous calls work without a key (30 requests/min) curl https://api.geoiphub.com/v1/lookup/8.8.8.8

Start Scoring Every IP in Real Time

GeoIPHub gives fraud, security, and engineering teams a single API for IP geolocation, VPN & proxy detection, threat intelligence, and an explainable 0–100 risk score.

Complete response on every lookup
VPN, proxy, residential-proxy & Tor detection
Explainable 0–100 IP risk score
Free tier with 1,500 requests/day

Get Your Free API Key

Sign up in minutes — no credit card required. Upgrade only when you need more volume.

Frequently Asked Questions

Can IP geolocation prevent cyber attacks?

IP geolocation is one layer of defense, not a complete solution. It can block requests from known malicious infrastructure, detect anonymization attempts, enforce geo-restrictions, flag login anomalies from impossible travel, and filter automated traffic, all before your application layer processes the request. What it cannot do is catch sophisticated attackers using residential proxies with clean reputations, or distinguish a real user from a compromised human device. Use it as a first-pass filter combined with behavioral and device signals.

What types of cyber attacks does IP geolocation help prevent?

IP geolocation is most effective against: credential stuffing attacks (bots hitting login forms from cloud and proxy IPs), account takeover via impossible travel (login from Berlin then Seoul in 5 minutes), geographic compliance violations (users bypassing geo-restrictions with VPNs), automated scanning and scraping from datacenter IPs, and click fraud or invalid traffic from known bot infrastructure. It is less effective against targeted attacks by sophisticated actors who use residential proxies to blend in with legitimate users.

How do I check if an IP is from a VPN or proxy?

An IP geolocation API with anonymization detection returns boolean fields (is_vpn, is_proxy, is_tor, is_residential_proxy) alongside the geolocation data. VPN detection works by cross-referencing the IP against published provider infrastructure lists and active protocol probing. Proxy detection uses port probing. Tor exit node detection uses the public Tor consensus directory. Residential proxies are the hard case: from an IP lookup alone they can only be inferred coarsely from network data, so treat an is_residential_proxy flag as a hint and corroborate it with device and behavioral signals.

What is impossible travel detection and how does it work?

Impossible travel detection flags account logins from two geographically separate locations within a time window that is physically impossible for a human to travel between. Example: a user logs in from London at 14:00, then from Singapore at 14:30. The 5,500-mile distance requires at minimum 13 hours of flight time, so either the London or Singapore login is from a different device or a stolen session. Implementation: store the IP geolocation at each login, calculate distance and elapsed time between consecutive logins, flag pairs where distance / time > 900 km/h (roughly the speed of commercial aircraft).

Should I block all traffic from certain countries?

Country-level blocking is a blunt instrument with significant collateral damage. Before blocking an entire country, verify whether you have legitimate users there, because a block you set once will also hit those users. More targeted alternatives: escalate to step-up verification for high-risk countries on sensitive flows (payment, password reset), use geo-restriction only where legally or contractually required, and combine country data with other signals (datacenter ASN, VPN detection) to target the infrastructure being abused rather than the population it appears to come from.

What is the difference between IP geolocation and IP intelligence for security?

IP geolocation returns location fields: country, region, city, coordinates. IP intelligence returns the full dossier: location plus infrastructure type (residential, datacenter, mobile), anonymization status (VPN, proxy, Tor, residential proxy), abuse history, blocklist presence, threat classifications, and a synthesized risk score. For security use cases, you almost always want IP intelligence, not just geolocation. The country field alone tells you almost nothing about whether a request is legitimate.