2015-07-19 58 views
2

我工作的一个程序机器人这种结构中管理隐私(我会包括哪些层的笑只做)大型程序

  • 层A - GUI简单的界面来处理按钮,游戏杆等。将这些值转换成命令发送到控制界面。

  • 层B - 控制从GUI数据库,并命令请求评估设备读/写的条目,以便计算用于数据库

  • 层C的新设备 - 写 - 条目 - 设备的数据库逻辑表示,创建书面和从设备

  • 层d读值的历史 - 硬件会谈物理硬件。将设备写入条目转换为命令并将它们发送到设备。使用设备中的值更新数据库设备读取条目。

我想创建一个java应用程序,其中没有图层能够调用超过一层以上或以下的功能。

是否有可能使用包隐私或像工厂这样的模式来创建项目结构,这使代码无法进入,让我们说层A,从层D或C导入任何东西?

回答

2

这不是您可以单独使用访问修饰符实现的功能。

你也不能通过(以某种方式)控制import ...因为Java语言不会对导入进行任何(额外)限制。 (import指令实际上只是语法糖,因此您无需在任何地方使用完全限定的名称。)

那么您还能做什么?

  • 您可以尝试实施运行时限制以防止错误的层访问工厂对象。但是这样的限制很容易被颠覆,故意或意外。

  • 您可以使用某种内部“能力”或“凭证”机制,但很难看出您将如何防止凭证泄漏。 (如果证书是由安全管理器管理(见下文)可能的工作,但是这使问题更加复杂。)

我认为你可以做到这将是实现一个自定义的唯一方法SecurityManager ,并在每次发生潜在的层交叉呼叫时执行安全检查。例如,安全管理器可能(虽然很昂贵)检查调用堆栈以查找调用它的方法/类/包。您还需要关闭可用于(平凡)颠覆安全管理器的某些反射操作。实质上,除了内环之外的所有内容都需要被视为“不可信”的代码。老实说,用一个具有“防黑客”安全性的JVM实现这种事情可能超出了凡人的能力。 (太阳/甲骨文还没有成功尚未....)


其他替代方案:

  • 依靠程序员的自律。

  • 依靠代码库的静态分析;例如通过记录访问规则的注释提供帮助。你需要编写你自己的代码分析器来做到这一点。

  • 在层之间使用地址空间分隔以及占用空间小且安全的API。 (我们不再谈论一个单一的常规JVM这里...)

+0

刚刚向Michael Aaron Safyan提出了同样的问题,但在您看来,这些昂贵/涉及的方法对于清晰的代码维护来说是否现实?还是程序员自律? – flakes

+0

如果您只关心代码可维护性,程序员纪律就足够了。 IMO。 –

2

TL; DR没有一个灵丹妙药解决了这个,但很多不同的工具来利用

有很多种不同的技术来隔离软件应用程序的不同部分,但我不认为有任何解决方案可以解决所有问题。一些构建系统可以限制目标之间的依赖关系(例如,Bazel在构建目标上具有visibility属性,可以阻止一个目标依赖于另一个目标,即使它们通过Java的类可见性彼此都可见),这些目标可以与Java内置可见性。例如:

// Foo.java 
package com.yourcompany.foo; 
public class Foo {} 

// Build rule for Foo.java 
java_library(
    name = "Foo", 
    srcs = ["Foo.java"], 
    # Restricts visibility to this directory, even though 
    # the class visibility was "public" 
    visibility = ["//visibility:private"], 
) 

// Bar.java 
package com.yourcompany.bar; 

import com.yourcompany.foo.Bar; // prevented by build visibility system 

public class Bar { 
    Foo foo = new Foo(); 
} 

另外,也可以使用接口来介导的逻辑组件之间的所有交互,并隐藏这些接口的实现(例如,仅通过服务注册表接口或通过接口依赖注入暴露实现)。例如,对于Dagger,可以创建用于每个层的单独component,这将允许你写类似的代码:

final class ControllerImpl implements Controller { 
    // Since "ControllerImpl" is instantiated/wired into the 
    // controller layer, the database dependency is available/
    // exposed for injection within this layer. The access control is 
    // strictly performed by the way the dependencies are wired. 
    @Inject 
    public ControllerImpl(Database database) { 
    // ... 
    } 
} 

除了上述,可以使用依赖关系分析/依赖性分析测试或commit钩子自动检测依赖性规则违规(并根据它们触发错误/拒绝提交)。例如,一个穷人的解决方案就是简单地扫描每个文件的包声明及其导入语句,然后采用一些启发式方法来检测不良依赖。

另一种方法是将不同的组件捆绑到单独的JAR中,并使用自定义的ClassLoader加载它们,这样可以防止使用反射进行非法访问(否则可能会绕过任何程序结构)。

除了自动化方法,手动方法也有其价值。手动方法包括在代码审查和审计期间执行的常规代码审查和策略。

总之,没有一个正确的答案。有必要结合使用几种不同的方法,具体取决于这种分离的重要性。

+0

哇,我不知道这实际上会有多大的问题!限制图层访问的想法是确保代码可维护。这些解决方案是否适合课外项目,这可能只会持续一年或两年的上限?或者像Stephen C所说的那样,“依靠程序员纪律”是一种更合适的方法? – flakes

+1

好的。如果它只是简洁而不是严格的隐私问题,那么通过接口调解控制,使用注入框架来管理依赖关系,手动约束应该是绰绰有余的,特别是如果代码库的大小合理/可管理的话。不过,如果你还没有选择构建系统,我会推荐Bazel(尽管我有点偏颇),如果你使用它,你还可以利用其可见性限制。但是如果你已经有了一个不同的构建系统,那么这种事情就不需要了。 –

+2

国际海事组织,他们不会建议一个“小”项目。但如果你的目标是建立一个有希望成为一个真正的安全生产准备平台的希望,你别无选择,只能提出一个生产质量的解决方案。不要认为人们还没有尝试......并且(客观地)失败。这是一个严重的难题。 –