50ab46dbe1
App layer (R1): bind frps NewProxy to token-owned subdomain (anti-hijack), default-deny unknown webhook ops, HMAC-verify stripe-stub billing webhook, enforce bandwidth quota kill-switch (Ping op), least-privilege table grants (migrations 0002/0003), GOTRUE_PASSWORD_MIN_LENGTH=12. Infra/net (R2): unpublish internal host ports (kong/pooler/analytics/frps-dash), read-only docker-socket-proxy for vector (no host breakout), on-demand-TLS allow-list authorizer, edge-block machine-only webhooks, no-new-privileges on custom containers. Secrets (R3): rotate Postgres password (all roles) + frps dashboard; replace predictable supavisor defaults; secrets externalized to gitignored .env. Med/Low (R4): security response headers (HSTS/XCTO/XFO/Referrer/Permissions/COOP), restrict frp proxy_type to http (no open relay), disable destructive redis commands, tighten frps.toml perms. No secrets committed; rotated values live only in gitignored .env files.
55 lines
2.2 KiB
PL/PgSQL
55 lines
2.2 KiB
PL/PgSQL
-- 0002: pentest remediation (A4/W3 privilege reduction, A3 quota default, W1 subscription rows)
|
|
BEGIN;
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- A4 / W3: authenticated users must NOT be able to UPDATE tunnels directly.
|
|
-- All legitimate writes (claim, token rotation, quota/usage, activation) go
|
|
-- through service-role server routes / workers. A direct grant let an owner
|
|
-- tamper with bytes_used, quota_bytes, is_active, token and subdomain.
|
|
-- ---------------------------------------------------------------------------
|
|
REVOKE UPDATE ON public.tunnels FROM authenticated;
|
|
DROP POLICY IF EXISTS tunnels_update_own ON public.tunnels;
|
|
-- SELECT (read-only dashboard) stays intact via tunnels_select_own.
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- A3: free-tier quota default 1 TiB -> 2 GiB, and shrink existing rows that
|
|
-- still carry the old default so the kill-switch is meaningful.
|
|
-- ---------------------------------------------------------------------------
|
|
ALTER TABLE public.tunnels ALTER COLUMN quota_bytes SET DEFAULT 2147483648;
|
|
UPDATE public.tunnels
|
|
SET quota_bytes = 2147483648
|
|
WHERE quota_bytes = 1099511627776;
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- W1 (enablement): ensure every user has a subscriptions row so the billing
|
|
-- webhook activation (PATCH by user) actually targets a row, and backfill
|
|
-- existing users.
|
|
-- ---------------------------------------------------------------------------
|
|
CREATE OR REPLACE FUNCTION public.handle_new_user()
|
|
RETURNS trigger
|
|
LANGUAGE plpgsql
|
|
SECURITY DEFINER
|
|
SET search_path = public
|
|
AS $$
|
|
BEGIN
|
|
INSERT INTO public.users_profile (user_id, email)
|
|
VALUES (NEW.id, NEW.email)
|
|
ON CONFLICT (user_id) DO NOTHING;
|
|
|
|
INSERT INTO public.subscriptions (user_id, plan, status)
|
|
VALUES (NEW.id, 'free', 'active')
|
|
ON CONFLICT (user_id) DO NOTHING;
|
|
|
|
RETURN NEW;
|
|
END;
|
|
$$;
|
|
|
|
REVOKE ALL ON FUNCTION public.handle_new_user() FROM PUBLIC;
|
|
GRANT EXECUTE ON FUNCTION public.handle_new_user() TO supabase_auth_admin;
|
|
|
|
INSERT INTO public.subscriptions (user_id, plan, status)
|
|
SELECT id, 'free', 'active' FROM auth.users
|
|
ON CONFLICT (user_id) DO NOTHING;
|
|
|
|
COMMIT;
|