我正在设计Flex中的应用程序,该应用程序连接到某些Web服务以执行一些金融交易。 Web服务使用https协议进行保护,并要求在每次请求时登录时创建用户令牌。这用于验证和授权用户。到现在为止还挺好。
诀窍在于,并非所有的Web服务都是粗粒度的。举个例子,我们可以有两种Web服务方法:EnoughFounds和Transfer。因此,只有在方法EnoughFounds回复“true”之后,才会执行Transfer。此逻辑在Flex应用程序代码中编程。
我呈现的场景如下:如果有人下载应用程序并对其进行反编译会怎样。然后修改代码,以便不执行步骤EnougFunds。或者也许写一个全新的客户端甚至可能在其他技术中执行Transfer而不通过EnoughFunds步骤。在执行Transfer时,将在服务器上授权和验证用户;但由于他正在使用他的真实证书,他将能够执行转移。他跳过的检查属于业务逻辑而不属于安全域。我需要以某种方式确保执行应用程序的代码是未修改的我编写的Flex代码和用户下载的代码。我怎样才能做到这一点?我知道我可以重写服务,以便在服务器上执行序列,但这意味着很大的努力,我正在寻找其他类型的解决方案。
在我看来,必须有一些安全机制来解决这个特殊问题。
请注意,我不是在寻找有关最佳实践的建议。我的要求是不要在服务器端改变任何东西。如何在不更改服务的情况下保护协议级别的序列?
这是一个大错误。必须在服务中检查任何重要的业务规则。必须是这样的,无论客户端做什么,服务都不会让任何不好的事情发生。
特别是,有一个EnoughFunds操作是有道理的,因为如果EnoughFunds返回false,你可以告诉用户他没有足够的资金。但是,转移操作必须检查是否有足够的资金,而不是依赖客户进行这样重要的检查。
让我加入这一点 - 我让孩子们反编译我的游戏并改变/编辑通过操纵http通信的工具来回发送的消息 - 这只适用于没有外部价值的游戏。我的用户实际上加载了fiddler和firefox标头工具来操纵服务调用,只是为了在每天重置自己的游戏板上获得高分。
我不禁想到如果我把金钱或“真正的”价值投入到混合中会发生什么。
不要相信客户端发送的任何数据...使用“enoughFunds”调用来更新您的用户界面,但是当进行“转移”阶段时,您需要完全在服务器端重新评估该调用 - 不要相信这只是因为客户要求转移你应该接受它。
如果不改变服务器端,就无法解决这个问题,因为正如所有其他答案都指出的那样,问题出在那里。此外,没有合适的协议也不会涉及更改服务器端。
将此与银行柜台的人进行比较是非常合适的。那个人向银行员工提交了一些凭证,证明她是谁以及她实际上拥有一些账户X.这就是登录。
现在,这个人想订购从账户X到Y的转账。无论她对可用资金说什么都不重要。如果她提交了银行总裁签署的文件,说她有足够的资金,银行仍然需要在转账之前进行检查,因为钱只需要在那里。
这意味着,即使你在协议中得到一个安全的序列逻辑,确保在“转移”之前调用“EnoughFunds”,并且只调用一次,不久之前,并且使用正确的参数,它仍然是客户端告诉银行“没关系,我有足够的资金”。永远不会削减它。
你可以得到的最接近的是相当于倾斜柜台的银行客户,指着员工的屏幕并说“看,在这里,在你的系统中,它说交易可以完成,因为有足够的资金”,i。即客户端可以可验证地重现服务器刚刚制作的EnoughFunds调用的时间,输入和输出,这是可以的,但是毫无意义。
因此,解决方案是在内部使用转移调用EnoughFunds,期间。如果客户需要知道,您可以在没有足够资金的情况下返回描述性异常/错误。
(来源:userfriendly.org)
老实说,我认为你需要认真重新评估你的发展计划。正如其他人如此正确地陈述,您不能依赖客户的诚信。
简而言之,在您可以控制的环境之外没有“安全,可靠的代码”之类的东西(即服务器 - 即便如此,它也是有争议的)。你根本不知道你正在与之交谈的软件,所以无论你如何“调整”一个应用程序层协议,你仍然无法保证一个坏的演员不会简单地用反向工程实现欺骗你你的'调整'协议。
您的“信任域”仅扩展到Web服务api,不再进一步。如果您的服务无法验证其操作的完整性,那么它是一个设计糟糕的服务。
我想你应该考虑一些事情:
首先,我同意其他答案 - 客户绝对是你的敌人,永远不应该被信任。还要扩展你提出的一些评论 - 即使“EnoughFunds”返回某种加密令牌,但是确保黑客仍然没有以10的数量调用它,并且随后的传输被激活了10000000。
方法必须是将原子业务逻辑放在一起,例如“EnoughFunds and Transfer”。
我建议也为每个服务器调用添加一个序列,以便永远不会重新执行旧的服务器调用,因为它们现在不按顺序执行。服务器应该将“下一个序列令牌”作为某种“加密”号码返回。这可以很简单地生成随机数并作为响应的一部分返回,同时还将其放在服务器会话中并在来自该客户端的任何后续调用中重新确认它。
同样,这个技巧不仅仅是一个安全措施,只是试图帮助避免过于容易的“小提琴”情况。
这可以与模糊API结合使用。如果您按名称调用Web服务(例如:EnoughFunds服务将被调用),逆向工程变得越来越容易。相反,做一些像枚举服务一样简单的事情,并通过中央控制器 - activateTask = 12?param1 = 200。这仍然很容易进行逆向工程,但是......如果你可以投资加密每个请求,那就更好了,看起来像:SFASDFsdq1231sd4DFGTRsdf2rDF
当然,任何这样的好请求加密,都应该基于session-id(通常是:登录身份验证令牌)