我在我的流星应用程序中发现了一个关于订阅的重要安全错误(也许方法也受此影响).
即使我使用该check包并check()确保在发布内部接收到正确的参数数据类型,我已经意识到如果用户恶意订阅具有错误参数数据类型的订阅,则它会影响使用相同订阅的所有其他用户,因为当恶意用户使用不正确的参数时,流星服务器未运行发布.
我怎么能阻止这个?
使用的包:
aldeed:collection2-core@2.0.1
audit-argument-checks@1.0.7
mdg:validated-method
Run Code Online (Sandbox Code Playgroud)
和npm
import { check, Match } from 'meteor/check';
服务器端:
Meteor.publish('postersPub', function postersPub(params) {
check(params, {
size: String,
section: String,
});
return Posters.find({
section: params.section,
size: params.size === 'large' ? 'large' : 'small',
}, {
// fields: { ... }
// sort: { ... }
});
});
Run Code Online (Sandbox Code Playgroud)
客户端:
// in the template:
Meteor.subscribe('postersPub', { size: 'large', section: 'movies' });
// Malicious user in the browser console:
Meteor.subscribe('postersPub', { size: undefined, section: '' });
Run Code Online (Sandbox Code Playgroud)
问题:恶意用户订阅阻止所有其他用户从他们的postersPub订阅中获得答案.
额外注意:我也尝试用一个包装检查块和整个出版物,try catch它不会改变效果.该错误从服务器控制台消失,但其他用户不断受到影响,并且没有从恶意用户正在影响的订阅中获取数据.
有一点需要了解check和字符串,它接受空字符串,就像''你在恶意的例子中基本显示的那样.
如果没有保证解决您的出版物问题,我至少可以建议您修改check代码并包含对非空字符串的检查.
可能的方法可能是:
import { check, Match } from 'meteor/check';
const nonEmptyString = Match.Where(str => typeof str === 'string' && str.length > 0);
Run Code Online (Sandbox Code Playgroud)
然后可以check像这样使用:
check(params, {
size: nonEmptyString,
section: nonEmptyString,
});
Run Code Online (Sandbox Code Playgroud)
您可能对接受的参数更严格,并将它们减少为有效条目的子集.例如:
const sizes = ['large', 'small'];
const nonEmptyString = str => typeof str === 'string' && str.length > 0;
const validSize = str => nonEmptyString(str) && sizes.indexOf( str) > -1;
check(params, {
size: Match.Where(validSize),
section: Match.Where(nonEmptyString),
});
Run Code Online (Sandbox Code Playgroud)
请注意,这也有助于您避免基于参数的查询逻辑.您可以更改以下代码
const posters = Posters.find({
section: params.section,
size: params.size === 'large' ? 'large' : 'small',
}, {
// fields: { ... }
// sort: { ... }
});
Run Code Online (Sandbox Code Playgroud)
至
const posters = Posters.find({
section: params.section,
size: params.size,
}, {
// fields: { ... }
// sort: { ... }
});
Run Code Online (Sandbox Code Playgroud)
因为该方法无论如何只接受其中一个large或small作为参数.
另一种可以支持你防止发布错误的模式是,this.ready()如果集合没有返回游标,则调用(无论出于何种原因,更好的是编写好的测试以防止你出现这些情况).
const posters = Posters.find({
section: params.section,
size: params.size === 'large' ? 'large' : 'small',
}, {
// fields: { ... }
// sort: { ... }
});
// if we have a cursor with count
if (posters && posters.count && posters.count() >= 0)
return posters;
// else signal the subscription
// that we are ready
this.ready();
Run Code Online (Sandbox Code Playgroud)
应用上述所有模式将使您的函数看起来像这样:
import { check, Match } from 'meteor/check';
const sizes = ['large', 'small'];
const nonEmptyString = str => typeof str === 'string' && str.length > 0;
const validSize = str => nonEmptyString(str) && sizes.indexOf( str) > -1;
Meteor.publish('postersPub', function postersPub(params) {
check(params, {
size: Match.Where(validSize),
section: Match.Where(nonEmptyString),
});
const posters = Posters.find({
section: params.section,
size: params.size,
}, {
// fields: { ... }
// sort: { ... }
});
// if we have a cursor with count
if (posters && posters.count && posters.count() >= 0)
return posters;
// else signal the subscription
// that we are ready
this.ready();
});
Run Code Online (Sandbox Code Playgroud)
我自己发现,通过良好的check匹配this.ready(),我的应用程序中出版物的问题已经减少到最低限度.