oauth-backend/addon/cleintsecret_check.py
2025-06-09 23:12:28 +09:00

52 lines
1.9 KiB
Python

from mitmproxy import http
from urllib.parse import urlparse, parse_qs
class ClientSecretChecker:
def is_oauth_uri(self, uri: str) -> bool:
qs = parse_qs(urlparse(uri).query)
keys = qs.keys()
return "client_id" in keys and ("client_secret" in keys or "client_secret" in uri)
def has_client_secret_in_uri(self, uri: str) -> bool:
qs = parse_qs(urlparse(uri).query)
return "client_secret" in qs
def is_post_with_client_secret(self, flow: http.HTTPFlow) -> bool:
if flow.request.method != "POST":
return False
content_type = flow.request.headers.get("Content-Type", "")
if "application/x-www-form-urlencoded" in content_type:
body = parse_qs(flow.request.get_text())
return "client_secret" in body
return False
def is_exposed_in_referer(self, flow: http.HTTPFlow) -> bool:
referer = flow.request.headers.get("Referer", "")
return "client_secret" in referer
def check_client_secret_leak(self, flow: http.HTTPFlow) -> list[str]:
messages = []
if self.has_client_secret_in_uri(flow.request.url):
messages.append("client_secret found in URL query string")
if self.is_post_with_client_secret(flow):
messages.append("client_secret found in POST body")
if self.is_exposed_in_referer(flow):
messages.append("client_secret exposed in Referer header")
return messages
async def request(self, flow: http.HTTPFlow) -> None:
try:
if not self.is_oauth_uri(flow.request.url):
return
issues = self.check_client_secret_leak(flow)
if issues:
print(f"[HIGH] OAuth Client Secret Exposure: {' | '.join(issues)}")
print(f"[URL] {flow.request.url}")
except Exception as e:
print(f"[ERROR] Client Secret Check failed: {e}")