PostgreSQL/Supabase行级安全:仅持对应文档ID允许读取如何实现
实现方案
前提注意:你使用的GUID必须是密码学安全的随机值(推荐UUID v4),长度足够、不可预测,这是整个方案的安全基础,避免被暴力枚举。
推荐方案:自定义函数限制查询(安全性更高)
该方案无需创建任何用户账号,从底层限制只能通过传入正确GUID获取对应数据,完全杜绝全表扫描的可能性。
步骤1:禁用settings表的公开直接访问
收回匿名、认证用户对settings表的所有默认权限,禁止直接访问表:
REVOKE ALL ON settings FROM anon, authenticated;
步骤2:创建专用查询函数
仅接收GUID作为入参,匹配成功才返回对应行数据:
CREATE OR REPLACE FUNCTION get_settings(guid uuid) RETURNS SETOF settings LANGUAGE plpgsql SECURITY DEFINER AS $$ BEGIN RETURN QUERY SELECT * FROM settings WHERE id = guid; END; $$;
给匿名用户开放该函数的执行权限:
GRANT EXECUTE ON FUNCTION get_settings(uuid) TO anon;
步骤3:调整前端调用逻辑
将原直接查表的逻辑替换为调用自定义函数即可:
// 原调用逻辑 // supabase.from('settings').select('*').eq('id', guid) // 替换为 const { data, error } = await supabase.rpc('get_settings', { guid: 你存在内存中的guid值 })
备选方案:RLS策略实现(无需修改前端调用逻辑)
如果希望保留原有的supabase.from('settings').select('*').eq('id', guid)调用方式,可通过行级安全策略实现:
步骤1:开启行级安全并配置基础权限
ALTER TABLE settings ENABLE ROW LEVEL SECURITY; REVOKE ALL ON settings FROM anon, authenticated; GRANT SELECT ON settings TO anon;
步骤2:创建匹配查询规则的RLS策略
限制仅当查询携带精确的ID匹配条件时,才返回对应行:
CREATE POLICY allow_select_by_exact_id ON settings FOR SELECT TO anon USING ( id = (string_to_array(split_part(current_query(), 'eq(''id'',', 2), ''')')::text[])[1]::uuid );
注意:该方案依赖Supabase JS客户端生成的查询格式固定,若后续客户端查询语法变动可能导致策略失效,优先推荐自定义函数方案。
额外安全建议:
- 给settings表的id字段添加唯一索引,既避免重复ID,也能提升查询效率
- 可在Supabase dashboard中配置API请求频率限制,防止恶意暴力枚举GUID
- 严格按照你的需求将GUID仅存储在浏览器内存中,不要存入localStorage、sessionStorage等持久化位置,降低XSS攻击泄露凭证的风险
内容的提问来源于stack exchange,提问作者Rune Jeppesen
相关产品推荐
相关产品推荐

