feat: Add GeoIP blocking for high-risk countries (RU, CN, KP, IR, BY, SY, VE, CU)

- Update security_service.py with BLOCKED_COUNTRIES list
- Add check_geoip() middleware in app.py
- Log blocked attempts with security alerts
- Uses MaxMind GeoLite2-Country database

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-01-14 22:11:53 +01:00
parent 1a06b6ab29
commit cb574851cf
2 changed files with 39 additions and 5 deletions

32
app.py
View File

@ -453,6 +453,38 @@ def get_or_create_analytics_session():
db.close()
@app.before_request
def check_geoip():
"""Block requests from high-risk countries (RU, CN, KP, IR, BY, SY, VE, CU)."""
# Skip static files and health checks
if request.path.startswith('/static') or request.path == '/health':
return
if not is_ip_allowed():
ip = request.headers.get('X-Forwarded-For', request.remote_addr)
if ip:
ip = ip.split(',')[0].strip()
from security_service import get_country_code
country = get_country_code(ip)
logger.warning(f"GEOIP_BLOCKED ip={ip} country={country} path={request.path}")
# Create alert for blocked access
try:
db = SessionLocal()
from security_service import create_security_alert
create_security_alert(
db, 'geo_blocked', 'low',
ip_address=ip,
details={'country': country, 'path': request.path, 'user_agent': request.user_agent.string[:200]}
)
db.commit()
db.close()
except Exception as e:
logger.error(f"Failed to create geo block alert: {e}")
abort(403)
@app.before_request
def track_page_view():
"""Track page views (excluding static files and API calls)"""

View File

@ -5,7 +5,7 @@ Norda Biznes - Security Service
Security utilities for NordaBiz platform:
- Audit logging (admin action tracking)
- Security alerting (email notifications)
- GeoIP blocking (Poland only)
- GeoIP blocking (block high-risk countries: RU, CN, KP, IR, BY, SY, VE, CU)
- 2FA (TOTP) helpers
Author: Norda Biznes Development Team
@ -180,8 +180,9 @@ def _send_alert_email(alert):
# GeoIP configuration
GEOIP_ENABLED = os.getenv('GEOIP_ENABLED', 'false').lower() == 'true'
GEOIP_DB_PATH = os.getenv('GEOIP_DB_PATH', '/var/lib/GeoIP/GeoLite2-Country.mmdb')
ALLOWED_COUNTRIES = {'PL'} # Only Poland allowed
GEOIP_DB_PATH = os.getenv('GEOIP_DB_PATH', '/var/www/nordabiznes/geoip/GeoLite2-Country.mmdb')
# Block high-risk countries (Russia, China, North Korea, Iran, etc.)
BLOCKED_COUNTRIES = {'RU', 'CN', 'KP', 'IR', 'BY', 'SY', 'VE', 'CU'}
GEOIP_WHITELIST = set(os.getenv('GEOIP_WHITELIST', '').split(',')) - {''} # Whitelisted IPs
# GeoIP reader (lazy loaded)
@ -233,7 +234,7 @@ def get_country_code(ip_address: str) -> str:
def is_ip_allowed(ip_address: str = None) -> bool:
"""
Check if an IP address is allowed (from Poland or whitelisted).
Check if an IP address is allowed (not from blocked high-risk countries).
Args:
ip_address: IP to check (defaults to current request IP)
@ -264,7 +265,8 @@ def is_ip_allowed(ip_address: str = None) -> bool:
if country is None:
return True
return country in ALLOWED_COUNTRIES
# Block high-risk countries
return country not in BLOCKED_COUNTRIES
def geoip_check():