如何用Firestore安全规则阻止文档ID含正斜杠的用户名创建?
解决Firestore用户名文档ID带前后斜杠的拦截问题
问题根源
Firestore会自动剔除文档ID开头/结尾的斜杠,导致安全规则里的{username}变量拿到的是处理后的纯用户名,没法直接识别客户端提交的原始ID是否带斜杠。另外你规则里的正则[[:alpha:]]*只匹配字母,和你要求的“仅含字母数字”不符,得改成[[:alnum:]]*。
可行解决方案
要在安全规则层面拦截这种情况,有两种可靠方法:
方法1:用文档字段校验原始输入
要求客户端创建usernames文档时,必须在data里加一个rawUsername字段,值就是用户输入的原始用户名(没被Firestore处理的)。然后在规则里校验文档ID和原始输入完全一致,同时修正正则:
function isSignedIn() { return request.auth.uid != null; } function existingData() { return resource.data; } match /usernames/{username} { allow get: if isSignedIn(); allow create: if isSignedIn() && // 确保文档ID和用户原始输入完全一致 username == request.data.rawUsername && username.size() >= 5 && username.size() <= 12 && // 修正为匹配字母+数字 username.matches("[[:alnum:]]*") && // 拦截违规词汇 !username.lower().matches(".*duck.*"); allow delete: if isSignedIn() && request.auth.uid == existingData().userId; }
如果用户提交的原始用户名带前后斜杠,处理后的文档ID(username变量)和request.data.rawUsername就会不一致,规则直接拦截创建。客户端必须传入原始用户名,没法绕过这个校验。
方法2:通过请求路径校验
利用Firebase规则的request.path属性,检查请求路径的结构是否合法。比如客户端提交/usernames//John52时,request.path会变成["usernames", "", "John52"],路径长度超过了正常的2层(集合+文档),可以通过这个判断拦截:
function isSignedIn() { return request.auth.uid != null; } function existingData() { return resource.data; } match /usernames/{username} { allow get: if isSignedIn(); allow create: if isSignedIn() && // 确保路径是严格的集合+文档两层结构 request.path.size() == 2 && // 确保路径中的文档ID和变量完全一致 request.path[1] == username && username.size() >= 5 && username.size() <= 12 && username.matches("[[:alnum:]]*") && !username.lower().matches(".*duck.*"); allow delete: if isSignedIn() && request.auth.uid == existingData().userId; }
这种方式不需要客户端额外传字段,但要注意Firestore路径解析的细节,连续斜杠会被拆成空字符串的路径段,通过检查路径长度就能过滤这类非法请求。
额外提示
- 客户端也要先做前置校验(比如禁止输入前后斜杠、校验字符范围),减少无效请求,但安全规则的校验必须保留——毕竟客户端逻辑可以被绕过。
- 正则
[[:alnum:]]匹配任意字母和数字,如果你需要更明确的范围(比如只允许英文大小写+数字),可以改成[a-zA-Z0-9]*。
内容的提问来源于stack exchange,提问作者k29
相关产品推荐
相关产品推荐

