Skip to content

Commit d942c4d

Browse files
committed
fix: disableHook API 增加签名机制
之前设置的值过于简单,导致请求容易被伪造,存在一定的 安全风险。 新的值会使用 masterKey 和时间签名,存储服务会校验值的 有效性,从而确定是否禁止触发 hook 函数。
1 parent 0a4f856 commit d942c4d

File tree

5 files changed

+113
-6
lines changed

5 files changed

+113
-6
lines changed

lib/av-extra.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ var qs = require('querystring');
77
var iconvlite = require('iconv-lite');
88
var AV = require('avoscloud-sdk').AV;
99
var utils = require('./utils');
10+
var crypto = require('crypto');
1011
var debug = require('debug')('AV:LeanEngine');
1112
var version = require('../package.json').version;
1213

@@ -285,11 +286,19 @@ AV.Cloud.httpRequest = function(options) {
285286
};
286287

287288
AV.Object.prototype.disableBeforeHook = function() {
288-
this.set('__before', new Date().getTime());
289+
this.set('__before', signDisableHook('__before_for_' + this.className, new Date().getTime()));
289290
};
290291

291292
AV.Object.prototype.disableAfterHook = function() {
292-
this.set('__after', new Date().getTime());
293+
this.set('__after', signDisableHook('__after_for_' + this.className, new Date().getTime()));
294+
};
295+
296+
var signDisableHook = function(hookName, ts) {
297+
var masterKey = process.env.LC_APP_MASTER_KEY;
298+
var sign = crypto.createHmac('sha1', masterKey)
299+
.update(hookName + ':' + ts)
300+
.digest('hex');
301+
return ts + ',' + sign;
293302
};
294303

295304
module.exports = AV;

lib/leanengine.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ var classHook = function(className, hook, object, user, meta, cb) {
361361

362362
try {
363363
if (hook.indexOf('__after_') === 0) {
364-
obj.disableAfterHook();
364+
setHookMark('__after', obj);
365365
// after 的 hook 不需要 response 参数,并且请求默认返回 ok
366366
Cloud.__code[hook + className]({
367367
user: user,
@@ -370,7 +370,7 @@ var classHook = function(className, hook, object, user, meta, cb) {
370370
});
371371
return cb(null, 'ok');
372372
} else {
373-
obj.disableBeforeHook();
373+
setHookMark('__before', obj);
374374
Cloud.__code[hook + className]({
375375
user: user,
376376
object: obj
@@ -397,6 +397,19 @@ var classHook = function(className, hook, object, user, meta, cb) {
397397
}
398398
};
399399

400+
var setHookMark = function(hookAction, obj) {
401+
var sign = obj.get(hookAction);
402+
if(sign) {
403+
obj.set(hookAction, sign);
404+
} else {
405+
if(hookAction.indexOf('__before') === 0) {
406+
obj.disableBeforeHook();
407+
} else if(hookAction.indexOf('__after') === 0) {
408+
obj.disableAfterHook();
409+
}
410+
}
411+
};
412+
400413
var onVerified = function(type, user) {
401414
try {
402415
Cloud.__code['__on_verified_' + type]({

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"expect.js ": "0.2.0",
2121
"express": "4.9.7",
2222
"mocha": "2.3.3",
23+
"rewire": "^2.5.1",
2324
"should": "3.3.2",
2425
"supertest": "0.14.0"
2526
},

test/av-extra_test.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
2-
var should = require('should'), // jshint ignore:line
3-
AV = require('../lib/av-extra');
2+
var should = require('should'); // jshint ignore:line
3+
var rewire = require("rewire");
4+
var AV = rewire('../lib/av-extra.js');
45

56
var express = require('express');
67
var bodyParser = require('body-parser');
@@ -55,4 +56,9 @@ describe('av-extra', function() {
5556
}
5657
});
5758
});
59+
60+
it('signDisableHook', function() {
61+
AV.__get__('signDisableHook')('__before_for_TestClass', 1453711871302).should.equal('1453711871302,177cbac6495f52e462aae2d054529e08a1725276');
62+
});
63+
5864
});

test/hook_test.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ AV.Cloud.beforeSave("TestClass", function(request, response) {
1717
}
1818
assert.equal(request.object.className, 'TestClass');
1919
request.object.set('user', request.user);
20+
should.exist(request.object.get('__before'));
2021
response.success();
2122
});
2223

@@ -70,6 +71,7 @@ AV.Cloud.afterSave("TestError", function() {
7071
AV.Cloud.afterUpdate("TestClass", function(request) {
7172
var bizTime = new Date();
7273
assert(request.object.updatedKeys.indexOf('foo') != -1);
74+
should.exist(request.object.get('__after'));
7375
request.object.set('bizTime', bizTime);
7476
request.object.save(null, {
7577
success: function(obj) {
@@ -86,6 +88,15 @@ AV.Cloud.beforeDelete("TestClass", function(request, response) {
8688
response.success();
8789
});
8890

91+
AV.Cloud.beforeSave("HookMarkTest", function(request, response) {
92+
should.exist(request.object.get('__before'));
93+
response.success(request.object);
94+
});
95+
96+
AV.Cloud.afterSave("HookMarkTest", function(request) {
97+
should.exist(request.object.get('__after'));
98+
});
99+
89100
AV.Cloud.onVerified('sms', function(request) {
90101
assert.equal(request.object.id, '54fd6a03e4b06c41e00b1f40');
91102
});
@@ -466,4 +477,71 @@ describe('hook', function() {
466477
});
467478
});
468479

480+
describe('hookMark', function() {
481+
it('before', function(done) {
482+
request(AV.Cloud)
483+
.post('/1/functions/HookMarkTest/beforeSave')
484+
.set('X-AVOSCloud-Application-Id', appId)
485+
.set('X-AVOSCloud-Application-Key', appKey)
486+
.set('Content-Type', 'application/json')
487+
.send({
488+
"object": {
489+
"foo": "bar",
490+
"__before": 'abcdefg'
491+
}
492+
})
493+
.expect(200)
494+
.end(function(err, res) {
495+
res.body.__before.should.equal('abcdefg');
496+
done();
497+
});
498+
});
499+
500+
it('before_no_attrib', function(done) {
501+
request(AV.Cloud)
502+
.post('/1/functions/HookMarkTest/beforeSave')
503+
.set('X-AVOSCloud-Application-Id', appId)
504+
.set('X-AVOSCloud-Application-Key', appKey)
505+
.set('Content-Type', 'application/json')
506+
.send({
507+
"object": {
508+
"foo": "bar"
509+
}
510+
})
511+
.expect(200)
512+
.end(function(err, res) {
513+
should.exist(res.body.__before);
514+
done();
515+
});
516+
});
517+
518+
it('after', function(done) {
519+
request(AV.Cloud)
520+
.post('/1/functions/HookMarkTest/afterSave')
521+
.set('X-AVOSCloud-Application-Id', appId)
522+
.set('X-AVOSCloud-Application-Key', appKey)
523+
.set('Content-Type', 'application/json')
524+
.send({
525+
"object": {
526+
"foo": "bar",
527+
"__after": 'abcdefg'
528+
}
529+
})
530+
.expect(200, done);
531+
});
532+
533+
it('after_no_attrib', function(done) {
534+
request(AV.Cloud)
535+
.post('/1/functions/HookMarkTest/afterSave')
536+
.set('X-AVOSCloud-Application-Id', appId)
537+
.set('X-AVOSCloud-Application-Key', appKey)
538+
.set('Content-Type', 'application/json')
539+
.send({
540+
"object": {
541+
"foo": "bar"
542+
}
543+
})
544+
.expect(200, done);
545+
});
546+
});
469547
});

0 commit comments

Comments
 (0)