Java 如何避免滥用REST端点

Java 如何避免滥用REST端点,java,javascript,rest,Java,Javascript,Rest,如何避免滥用RESTAPI?例如,我有一个网站,在这个网站上,某些动作可以赚取一堆积分,这些积分存储在一个用户帐户中。因此,从技术上讲,每当执行此操作时,我都会调用我的REST端点将点添加到用户帐户中。动作本身只在网站内发生,因此无法从后端检查动作是否真的发生 如何避免有人使用Javascript调试器查找调用并直接触发它以进行欺骗。。。 有什么原则可以避免这种滥用吗 编辑:下面是一个缩小问题范围的示例:例如,我们有一个等待队列,您可以通过推特页面来缩短等待时间。twittersdk有一个回调方

如何避免滥用RESTAPI?例如,我有一个网站,在这个网站上,某些动作可以赚取一堆积分,这些积分存储在一个用户帐户中。因此,从技术上讲,每当执行此操作时,我都会调用我的REST端点将点添加到用户帐户中。动作本身只在网站内发生,因此无法从后端检查动作是否真的发生

如何避免有人使用Javascript调试器查找调用并直接触发它以进行欺骗。。。 有什么原则可以避免这种滥用吗

编辑:下面是一个缩小问题范围的示例:例如,我们有一个等待队列,您可以通过推特页面来缩短等待时间。twittersdk有一个回调方法,当用户发送tweet时会触发该方法。发生这种情况时,将调用后端,例如api.somedomain.net/user/xyz123?hastweeed=1或类似


所以我的问题是,如何保护对api.somedomain.net的最后一步调用,因为有人可以查找此REST url并手动触发调用,而无需创建tweet。

我不会直接从Javascript调用api。如果有一种方法可以滥用它,那么它肯定会在某个时候滥用


我会尝试将前端调用迁移到后端。

我不会直接从Javascript调用API。如果有一种方法可以滥用它,那么它肯定会在某个时候滥用


我会尝试将前端调用迁移到后端。

答案很简单:不要将UI用作用户的最终状态。堆栈溢出实际上就是一个很好的例子。当我投票支持您的问题时,UI仅在对后端的REST调用成功完成且没有错误后才更新。因此,在更新状态之前,您应该等待每个REST调用成功完成

如果有人试图使用JavaScript控制台攻击网页,同样的逻辑也应该适用。REST服务不知道请求从何而来,但您的逻辑应该防止恶意使用,无论是有意还是无意

编辑:


您的示例问题的解决方案是使用一个REST调用来发送关于页面的推文,从而从服务器端代码向Twitter发出实际的REST调用。HasTweetd计数只有在完成对Twitter API的完整且成功的调用后才会增加。这仍然为恶意用户打开了大门,他们可能会发布推特,但推特可能已经采取了一些措施来防止这种情况。

答案很简单:不要将用户界面作为用户的最终状态。堆栈溢出实际上就是一个很好的例子。当我投票支持您的问题时,UI仅在对后端的REST调用成功完成且没有错误后才更新。因此,在更新状态之前,您应该等待每个REST调用成功完成

如果有人试图使用JavaScript控制台攻击网页,同样的逻辑也应该适用。REST服务不知道请求从何而来,但您的逻辑应该防止恶意使用,无论是有意还是无意

编辑:


您的示例问题的解决方案是使用一个REST调用来发送关于页面的推文,从而从服务器端代码向Twitter发出实际的REST调用。HasTweetd计数只有在完成对Twitter API的完整且成功的调用后才会增加。这仍然为恶意用户打开了大门,他们可能会发出推特,但推特可能已经采取了一些措施来防止这种情况。

您可以使用预先生成的随机密钥,但过期时间有限

将该键发送到html数据属性中的浏览器,并检查它们是否仅使用一次,如果未使用,请在几次后将其删除

编辑:javascript中的简单示例

var keyRing = (function(){
    var maxLifeTime = 900000; // 15 mins.
    var topRing = Math.pow(2,53);
    var keyRing = {
        idx: {},
        ring: [],
        top: 0, 
        bottom: 0,
    };

    function randomId(){
        return String(Math.random()).replace(/^0\./, '');
    };

    return { 
        get: function getKey(){
            var k = randomId(); // Generate new key.
            if (keyRing.idx[k]) return getKey(); // Avoid duplication (Almost impossible)
            var now = (new Date()).getTime();
            var expT = now + maxLifeTime; // Calculate expiration time.

            // Annotate in keyring:
            keyRing.idx[k] = true;
            keyRing.ring[keyRing.top++] = [expT, k];
            keyRing.top = keyRing.top % topRing; // Loop.

            // Discard expired:
            for (
                var i = keyRing.bottom; 
                i != keyRing.top;
                i = ++i % topRing
            ) { 
                if (keyRing.ring[i][0] > now) {
                    keyRing.bottom = i; // Update lower bound.
                    break; // Stop on first unexpired.
                };
                delete(keyRing.idx[keyRing.ring[i][1]]);
                delete(keyRing.ring[i]);
            };

            return k;
        },      
        check: function checkKey(k){
            if (keyRing.idx[k]) {
                delete(keyRing.idx[k]); // Discard.
                return true;
            }; 
            return false;
        },      
    };          
})();       

var k = keyRing.get();
var l = keyRing.get();

console.log (keyRing.check("12489172349")); // False (Hope!)
console.log (keyRing.check(k)); // True
console.log (keyRing.check(k)); // False
console.log (keyRing.check(l)); // True
console.log (keyRing.check(l)); // False

您可以在有限的过期时间内使用预生成的随机密钥

将该键发送到html数据属性中的浏览器,并检查它们是否仅使用一次,如果未使用,请在几次后将其删除

编辑:javascript中的简单示例

var keyRing = (function(){
    var maxLifeTime = 900000; // 15 mins.
    var topRing = Math.pow(2,53);
    var keyRing = {
        idx: {},
        ring: [],
        top: 0, 
        bottom: 0,
    };

    function randomId(){
        return String(Math.random()).replace(/^0\./, '');
    };

    return { 
        get: function getKey(){
            var k = randomId(); // Generate new key.
            if (keyRing.idx[k]) return getKey(); // Avoid duplication (Almost impossible)
            var now = (new Date()).getTime();
            var expT = now + maxLifeTime; // Calculate expiration time.

            // Annotate in keyring:
            keyRing.idx[k] = true;
            keyRing.ring[keyRing.top++] = [expT, k];
            keyRing.top = keyRing.top % topRing; // Loop.

            // Discard expired:
            for (
                var i = keyRing.bottom; 
                i != keyRing.top;
                i = ++i % topRing
            ) { 
                if (keyRing.ring[i][0] > now) {
                    keyRing.bottom = i; // Update lower bound.
                    break; // Stop on first unexpired.
                };
                delete(keyRing.idx[keyRing.ring[i][1]]);
                delete(keyRing.ring[i]);
            };

            return k;
        },      
        check: function checkKey(k){
            if (keyRing.idx[k]) {
                delete(keyRing.idx[k]); // Discard.
                return true;
            }; 
            return false;
        },      
    };          
})();       

var k = keyRing.get();
var l = keyRing.get();

console.log (keyRing.check("12489172349")); // False (Hope!)
console.log (keyRing.check(k)); // True
console.log (keyRing.check(k)); // False
console.log (keyRing.check(l)); // True
console.log (keyRing.check(l)); // False

但是,对于一个简单的计数器来说,逻辑是什么?当我有一个REST端点,它只是将计数增加一次,每次调用它时,由纯Javascript的操作触发,我目前看不到在REST服务范围内验证它的方法。部分同意你的观点。也许我错过了什么。OP如何防止有人从UI嗅探HTTP数据包并重新发送它?理想情况下,在浏览器和服务器之间发送数据包时,应该对数据包进行加密。因此,即使有人嗅了嗅,他也不应该能够破译其中包含的内容,甚至无法破译数据包的开始或结束位置。嗯,说实话,这是我在做类似事情时想到的一个案例,但确实可以通过

一些后端逻辑。所以这或多或少是理论上的。但我想到的是浏览器游戏和类似的东西。好吧,我们正在取得进展。请用一个例子更新您的OP,其中您正在捕获用户点击,例如发射武器等,并且您试图阻止有人入侵控制台。但是,对于一个简单的计数器,逻辑是什么?当我有一个REST端点,它只是将计数增加一次,每次调用它时,由纯Javascript的操作触发,我目前看不到在REST服务范围内验证它的方法。部分同意你的观点。也许我错过了什么。OP如何防止有人从UI嗅探HTTP数据包并重新发送它?理想情况下,在浏览器和服务器之间发送数据包时,应该对数据包进行加密。因此,即使有人嗅了嗅,他也不应该能够破译其中包含的内容,甚至无法破译数据包的开始或结束位置。嗯,没错,这是我在做类似事情时想到的情况,但确实可以通过一些后端逻辑来处理。所以这或多或少是理论上的。但我想到的是浏览器游戏和类似的东西。好吧,我们正在取得进展。请用一个例子更新您的OP,其中您正在捕获用户点击,例如发射武器等,并且您正在试图阻止有人入侵控制台。您能再解释一下吗?我担心我还不能理解…用户在JS中单击,这会向服务器发出请求,服务器调用REST API,然后服务器从API中读取响应,如果需要,解析它,并将响应返回给用户,JS会更新界面。您能再解释一下吗?我担心我还不能跟上…用户在JS中单击,向服务器发出请求,服务器调用REST API,然后服务器从API读取响应,如果需要,解析它,并将响应返回给用户,其中JS更新接口。在JS中调用Rest端点,以便在成功案例中更新UI,否则您将能够显示错误消息。我假设您在递增计数器之前未对用户进行身份验证?还有一个事实是,它的REST,如果您引入任何技巧,如令牌或任何东西,那么它将违反REST的无状态原则调用js中的REST端点,以便在成功案例中更新UI,否则您将能够显示错误消息。我假设您在增加计数器之前没有对用户进行身份验证?还有一个事实是,它的REST,如果你引入任何技巧,如令牌或任何东西,那么它将违反REST的无状态原则。你能提供更多细节或链接吗?添加了javascript中的简单示例。希望会有帮助。你能提供更多的细节或链接吗?添加了简单的javascript示例。希望会有所帮助。