【问题标题】:How to prevent malicious Meteor subscriptions using check如何使用检查防止恶意 Meteor 订阅
【发布时间】:2018-04-09 18:25:05
【问题描述】:

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

尽管我使用check 包和check() 确保在发布中接收到正确的参数数据类型,但我已经意识到,如果用户使用错误的参数数据类型恶意订阅该订阅,它会影响所有使用相同订阅的其他用户,因为当恶意用户使用不正确的参数时,流星服务器没有运行发布。

我怎样才能防止这种情况发生?

使用的包:

aldeed:collection2-core@2.0.1
audit-argument-checks@1.0.7
mdg:validated-method

和 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: { ... }
    });
});

客户端:

// in the template:
Meteor.subscribe('postersPub', { size: 'large', section: 'movies' });

// Malicious user in the browser console:
Meteor.subscribe('postersPub', { size: undefined, section: '' });

问题:恶意用户订阅正在阻止所有其他用户从他们的postersPub 订阅中获得答案。

额外说明:我还尝试使用try catch 包装检查块和整个出版物,但它不会改变效果。错误从服务器控制台消失,但其他用户继续受到影响,并且没有从恶意用户正在影响的订阅中获取数据。

【问题讨论】:

  • 没有看到代码很难说什么,但是为什么您不检查客户端是否发送了正确的数据。此外,如果您的出版物与用户相关,您需要用户 this.userId
  • 嗨,Maxim,酒吧与用户无关
  • @MaximPokrovskii 我添加了更多代码和解释
  • 还值得一提的是,meteor 服务器没有中断,但它确实阻止了从受影响的出版物发送的数据
  • 您提到了一个错误,但不要将其包含在您的问题中。该错误是什么以及它如何影响其他用户?您可以随时进一步验证出版物中的论点。

标签: security meteor


【解决方案1】:

检查方法和空字符串

关于check 和字符串有一点需要了解,那就是它接受像'' 这样的空字符串,您在恶意示例中基本上展示了这些字符串。

在不保证解决您的发布问题的情况下,我至少可以建议您修改您的 check 代码并检查非空字符串。

一种可能的方法是:

import { check, Match } from 'meteor/check';

const nonEmptyString = Match.Where(str => typeof str === 'string' && str.length > 0);

然后可以像这样在check 中使用:

check(params, {
    size: nonEmptyString,
    section: nonEmptyString,
});


更严格的检查

您可能对接受的参数更加严格,并将它们减少为有效条目的子集。例如:

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),
});

注意,这也有助于避免基于参数的查询逻辑。您可以更改以下代码

const posters = Posters.find({
    section: params.section,
    size: params.size === 'large' ? 'large' : 'small',
}, {
    // fields: { ... }
    // sort: { ... }
});

const posters = Posters.find({
    section: params.section,
    size: params.size,
}, {
    // fields: { ... }
    // sort: { ... }
});

因为无论如何该方法只接受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();


组合代码示例

应用所有上述模式将使您的函数看起来像这样:

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();
});


总结

我自己发现,通过良好的check 匹配和this.ready(),我的应用程序中的发布问题已降至最低。

【讨论】:

  • @w3jimmy 这是否可以帮助您以某种方式解决您的问题?
  • 感谢@Jankapunkt,我找到了问题的原因,但您的回答足以标记为正确(请参阅上面的评论)
猜你喜欢
  • 1970-01-01
  • 2013-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-28
  • 1970-01-01
  • 1970-01-01
  • 2019-02-01
相关资源
最近更新 更多