如何使用check来防止恶意Meteor订阅

w3j*_*mmy 2 security meteor

我在我的流星应用程序中发现了一个关于订阅的重要安全错误(也许方法也受此影响).

即使我使用该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它不会改变效果.该错误从服务器控制台消失,但其他用户不断受到影响,并且没有从恶意用户正在影响的订阅中获取数据.

Jan*_*nkt 5

检查方法和空字符串

有一点需要了解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)

因为该方法无论如何只接受其中一个largesmall作为参数.


回溯出版物中未定义的游标

另一种可以支持你防止发布错误的模式是,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(),我的应用程序中出版物的问题已经减少到最低限度.