Files
securelens-backend/app/services/scanner/cookies.py
2026-04-07 18:13:43 +05:30

71 lines
2.7 KiB
Python

import logging
from http.cookies import SimpleCookie
import httpx
from app.schemas.scan import Issue
from app.services.scanner.base import BaseScanner
logger = logging.getLogger(__name__)
class CookieScanner(BaseScanner):
async def scan(self, url: str, response: httpx.Response) -> list[Issue]:
issues: list[Issue] = []
is_https = url.startswith("https")
raw_cookies = response.headers.multi_items()
set_cookie_headers = [
value for key, value in raw_cookies if key.lower() == "set-cookie"
]
if not set_cookie_headers:
return issues
for cookie_str in set_cookie_headers:
cookie_lower = cookie_str.lower()
cookie = SimpleCookie()
try:
cookie.load(cookie_str)
except Exception:
logger.debug(f"Could not parse cookie: {cookie_str[:80]}")
continue
for name, morsel in cookie.items():
if "httponly" not in cookie_lower:
issues.append(Issue(
issue=f"Cookie '{name}' missing HttpOnly flag",
severity="Warning",
layer="Cookie Security",
fix=f"Set the HttpOnly flag on cookie '{name}' to prevent JavaScript access",
))
if "; secure" not in cookie_lower:
if is_https:
issues.append(Issue(
issue=f"Cookie '{name}' missing Secure flag",
severity="Warning",
layer="Cookie Security",
fix=f"Set the Secure flag on cookie '{name}' to ensure it is only sent over HTTPS",
))
samesite_value = morsel.get("samesite", "").lower()
if not samesite_value:
issues.append(Issue(
issue=f"Cookie '{name}' missing SameSite attribute",
severity="Warning",
layer="Cookie Security",
fix=f"Set SameSite=Lax or SameSite=Strict on cookie '{name}' to prevent CSRF attacks",
))
elif samesite_value == "none":
if "; secure" not in cookie_lower:
issues.append(Issue(
issue=f"Cookie '{name}' has SameSite=None without Secure flag",
severity="Critical",
layer="Cookie Security",
fix=f"Cookies with SameSite=None must also have the Secure flag set",
))
return issues