fix(security): timing attack, rate limiter за прокси, хардкод ID в скриптах (20.09.2026)
This commit is contained in:
@@ -58,7 +58,7 @@ async def verify_telegram_initdata(init_data: str):
|
||||
hashlib.sha256
|
||||
).hexdigest()
|
||||
|
||||
if calculated_hash != received_hash:
|
||||
if not hmac.compare_digest(calculated_hash, received_hash):
|
||||
raise HTTPException(401, "Invalid initData signature")
|
||||
|
||||
# Извлекаем данные пользователя
|
||||
|
||||
+30
-2
@@ -3,14 +3,42 @@
|
||||
Очищает ВСЕ данные по играм, урокам, чат-учителю, достижениям.
|
||||
Не трогает: users (остаётся), tts_cache (аудио).
|
||||
|
||||
Запуск: python3 full_reset.py
|
||||
Запуск: python3 full_reset.py <USER_ID>
|
||||
|
||||
🔧 ФИКС (20.09.2026): убран хардкод USER_ID — теперь через аргумент + подтверждение.
|
||||
Раньше: USER_ID = 6694989403 (мог случайно снести прогресс на проде).
|
||||
Теперь: python3 full_reset.py 123456789 → запросит подтверждение "YES".
|
||||
"""
|
||||
import asyncio
|
||||
import sys
|
||||
|
||||
import asyncpg
|
||||
|
||||
from config import DB_CONFIG
|
||||
|
||||
USER_ID = 6694989403
|
||||
|
||||
# ============ Проверка аргументов ============
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("❌ Использование: python3 full_reset.py <USER_ID>")
|
||||
print(" Пример: python3 full_reset.py 6694989403")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
USER_ID = int(sys.argv[1])
|
||||
except ValueError:
|
||||
print(f"❌ USER_ID должен быть числом, получено: {sys.argv[1]}")
|
||||
sys.exit(1)
|
||||
|
||||
confirm = input(
|
||||
f"⚠️ Удалить ВСЕ данные пользователя {USER_ID}? Напиши YES для подтверждения: "
|
||||
)
|
||||
if confirm != "YES":
|
||||
print("❌ Отменено.")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
# ============ Основная логика ============
|
||||
|
||||
async def main():
|
||||
pool = await asyncpg.create_pool(**DB_CONFIG)
|
||||
|
||||
@@ -128,8 +128,16 @@ async def rate_limit_middleware(request: Request, call_next):
|
||||
if path in ["/", "/health"]:
|
||||
return await call_next(request)
|
||||
|
||||
# 🔧 ФИКС (20.09.2026): за Cloudflare/nginx request.client.host — IP прокси.
|
||||
# Берём реальный IP из X-Forwarded-For (первый адрес).
|
||||
forwarded = request.headers.get("x-forwarded-for")
|
||||
if forwarded:
|
||||
client_ip = forwarded.split(",")[0].strip()
|
||||
elif request.headers.get("cf-connecting-ip"):
|
||||
client_ip = request.headers.get("cf-connecting-ip")
|
||||
else:
|
||||
client_ip = request.client.host if request.client else "unknown"
|
||||
rate_key = f"{client_ip}:{path}"
|
||||
rate_key = f"{client_ip}:{path}"
|
||||
|
||||
if not rate_limiter.is_allowed(rate_key, path):
|
||||
retry_after = rate_limiter.get_retry_after(rate_key, path)
|
||||
|
||||
+31
-3
@@ -3,15 +3,43 @@
|
||||
Очищает: user_learning_answers, user_lesson_progress, user_topic_progress,
|
||||
user_skill_mastery, learning_sessions, teacher_chat_history, teacher_ai_usage.
|
||||
|
||||
Запуск: python3 reset_my_progress.py
|
||||
Запуск: python3 reset_my_progress.py <USER_ID>
|
||||
|
||||
🔧 ФИКС (20.09.2026): убран хардкод USER_ID — теперь через аргумент + подтверждение.
|
||||
Раньше: USER_ID = 6694989403 (мог случайно снести прогресс на проде).
|
||||
Теперь: python3 reset_my_progress.py 123456789 → запросит подтверждение "YES".
|
||||
"""
|
||||
import asyncio
|
||||
import sys
|
||||
|
||||
import asyncpg
|
||||
|
||||
from config import DB_CONFIG
|
||||
|
||||
# ID пользователя для сброса (твой Telegram ID)
|
||||
USER_ID = 6694989403
|
||||
|
||||
# ============ Проверка аргументов ============
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("❌ Использование: python3 reset_my_progress.py <USER_ID>")
|
||||
print(" Пример: python3 reset_my_progress.py 6694989403")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
USER_ID = int(sys.argv[1])
|
||||
except ValueError:
|
||||
print(f"❌ USER_ID должен быть числом, получено: {sys.argv[1]}")
|
||||
sys.exit(1)
|
||||
|
||||
confirm = input(
|
||||
f"⚠️ Сбросить прогресс «Учитель» и «Уроки» для пользователя {USER_ID}? "
|
||||
f"Напиши YES для подтверждения: "
|
||||
)
|
||||
if confirm != "YES":
|
||||
print("❌ Отменено.")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
# ============ Основная логика ============
|
||||
|
||||
async def main():
|
||||
pool = await asyncpg.create_pool(**DB_CONFIG)
|
||||
|
||||
Reference in New Issue
Block a user