权限控制必须落在后端,前端隐藏只是障眼法;后端需关闭非GET权限,前端仅负责体验收敛,SQL界面须解析拦截非SELECT语句并使用只读数据库账号。
只读界面的核心判断:权限控制必须落在后端,前端隐藏只是障眼法
用户看到的“没有按钮”不等于安全。只要接口仍可被调用,绕过前端限制发 put、delete 或直接请求 /api/v1/datasets/123 就能修改数据。所以第一步永远是后端关闭非 get 权限——比如在 django rest framework 中给视图集设置 permission_classes = [isauthenticated, isreadonly];或在 fastapi 中用依赖项校验 depends(readonly_user)。前端所有操作(包括右键、快捷键、地址栏跳转)都不可信,只负责体验收敛。
React 项目中批量移除编辑入口的实操路径
假设你用的是基于 Ant Design 的仪表盘,常见编辑入口藏在这些位置:
-
Table的rowSelection和操作列里的编辑/删除按钮 —— 直接删掉render中返回<button type="link" onclick="{...}">编辑</button>的逻辑,或统一用columns.filter(col => col.key !== 'action') -
Form组件本身 —— 不要渲染<form onfinish="{...}"></form>,改用<descriptions></descriptions>或只读<form.item></form.item>配合valuePropName="children"和禁用状态 - 顶部工具栏的
新增、导入、导出(含写入)按钮 —— 删除对应<button onclick="{handleCreate}"></button>,保留纯下载类exportAsCSV(注意它只触发GET请求) - URL 路由中带编辑语义的路径,如
/datasets/:id/edit—— 从routes.tsx中移除该路由,或重定向到详情页
SQL 查询界面如何防止误执行或注入式修改
分析师常需写 SELECT 查数据,但输入框若未限制,可能手滑敲出 UPDATE 或 DROP。关键动作不是“禁用提交按钮”,而是:
- 在 SQL 解析层拦截非
SELECT语句 —— 用正则粗筛(^\s*SELECT\b,注意大小写和换行),或引入轻量解析器如sql-parser校验 AST 节点类型 - 连接数据库时使用只读账号:PostgreSQL 中建角色
CREATE ROLE analyst WITH NOSUPERUSER NOCREATEDB NOCREATEROLE;并GRANT SELECT ON ALL TABLES IN SCHEMA public TO analyst; - 前端禁用
textarea的Ctrl+Enter提交,或监听keydown拦截UPDATE/INSERT关键字输入(仅辅助,不替代后端校验) - 执行结果表格禁用 inline 编辑(如
EditableTable的editable属性设为false)
仪表盘(Dashboard)里那些容易被忽略的“隐性可写点”
看起来静态的图表,也可能埋着修改入口:
- 图表右上角的
⋯菜单 —— 检查是否含编辑图表、修改筛选器,这类功能应整体移除或灰掉 - 时间范围选择器(
RangePicker)如果绑定了实时刷新逻辑,可能触发后台重查 —— 确保它只更新本地状态,不自动调用fetchData({ timeRange });或把onChange替换为onOpenChange防抖 - URL 中的
?filter=xxx参数若被前端解析并拼进请求体,可能被手动篡改 —— 后端必须校验该参数是否属于预设白名单(如['status', 'region']),否则拒绝响应 - 导出按钮若生成服务端报表(如 PDF),确认模板中不含用户可控字段的动态插入,避免模板注入
最麻烦的从来不是“怎么去掉按钮”,而是“怎么确认没漏掉任何一条通往写操作的链路”。尤其当系统有多个前端入口(Web / Electron / 内嵌 iframe)、多种身份切换逻辑时,建议用 Burp Suite 抓一遍完整操作流,比对每条请求方法与权限声明是否一致。










