做java';s的内部类会带来安全风险吗?
最近,我项目的安全团队发布了一份安全代码指南文档,该文档旨在作为我们代码审查的一部分。首先让我印象深刻的是一条写着“不要使用内部类”的条款。我认为这似乎是一个非常严厉和笼统的声明。如果使用正确的话,内部类是很好的,对吗?但是我在谷歌上搜索了一下,找到了,这里引用是为了方便 规则5:不要使用内部类 一些Java语言书籍说 内部类只能由用户访问 包围它们的外部类。 事实并非如此。Java字节码具有 没有内部类的概念,所以内部 类由编译器翻译 进入普通的班级 可以访问同一版本中的任何代码 包裹第四条规则说不要依赖 关于包装的保护范围 但是等等,情况变得更糟了。内心 类获取对 包含外部类,即使这些 字段被声明为私有。和 内部类被转换为 单独上课。为了让这个 对字段的单独类访问 外部类,编译器静默运行 将这些字段从私有更改为 包装范围!这已经够糟糕的了 内部类是暴露的,但它是 更糟糕的是,编译器是 默默地推翻你的决定 将一些字段设置为私有。不要使用 如果可以的话,可以使用内部类。 (讽刺的是,新的Java 2 doPrivileged()API使用指南 建议您使用一个内部类来 编写特权代码,这就是其中之一 为什么我们不喜欢这个 doPrivileged()API。) 我的问题是做java';s的内部类会带来安全风险吗?,java,security,inner-classes,Java,Security,Inner Classes,最近,我项目的安全团队发布了一份安全代码指南文档,该文档旨在作为我们代码审查的一部分。首先让我印象深刻的是一条写着“不要使用内部类”的条款。我认为这似乎是一个非常严厉和笼统的声明。如果使用正确的话,内部类是很好的,对吗?但是我在谷歌上搜索了一下,找到了,这里引用是为了方便 规则5:不要使用内部类 一些Java语言书籍说 内部类只能由用户访问 包围它们的外部类。 事实并非如此。Java字节码具有 没有内部类的概念,所以内部 类由编译器翻译 进入普通的班级 可以访问同一版本中的任何代码 包裹第四条规
在代码中使用这种安全性的想法有点愚蠢。如果需要代码级安全性,请使用模糊处理工具。正如@skaffman在上面的评论中所说,“代码可见性从来都不是一个安全特性。即使是私有成员也可以使用反射进行访问。” 如果您正在分发编译后的代码,并且没有对其进行混淆,那么如果您担心有人修补您的隐私,那么使用内部类是您最后的担忧 如果你正在托管你的代码,那么为什么你会担心有人窥探你的内部类呢 如果您要链接一些您不信任的第三方代码,并且在运行时无法检查这些代码,那么就对其进行沙箱处理
正如上面所说的,如果这是你公司的一个政策,请及时向你的公司报告 < P>你应该考虑你的申请需要提供什么样的安全性。具有安全体系结构的应用程序不会遇到这些命名问题 如果不允许用户对代码执行某些操作,则必须将此功能分离,并在服务器上运行(用户无权访问类文件)
请记住,您始终可以反编译java类文件。不要依赖“默默无闻的安全”。即使是模糊的代码也可以被分析、理解和修改。恶意代码可以使用java反射来获取JVM中的任何信息,除非有安全管理器禁止这样做,这包括将私有字段更改为公共字段等等
我个人的观点是,不这样做的原因被其他可能性所压倒,因此如果您需要它,使用内部类是有意义的,也是可读的。请注意,列出的缺点不适用于
静态
内部类,因为它们没有隐式访问其封闭类(或真正的对象)的权限
因此,如果这条规则对您的公司有所帮助,那么最好将静态内部类排除在外,因为它们提供了一种封装方法,在许多情况下都很有用
@Tom引用了“成员类可能是静态的,在这种情况下,它们无法访问周围类的实例变量”这一信息已经过时了大约十年。通过
AccessController.doPrivileged
广泛使用匿名内部类应该是一个线索。(如果不喜欢API,考虑<代码>的比例,尝试 >代码>最后< /COD>在JDK中不正确丢失的块)
策略是,如果两个类由不同的类加载器加载或具有不同的证书,则它们不能共享同一个包。为了获得更多的保护,请在罐子的清单中将包装标记为密封的。因此,从安全的角度来看,“规则4”是假的,因此这条规则也是假的
在任何情况下,制定安全策略时,您都应该了解您要防范的是什么。这些策略用于处理可能具有不同信任级别的移动代码(移动的代码)。除非您正在处理移动代码,或者您的代码将被放入可能需要的库中,否则这些预防措施没有什么意义。然而,使用健壮的编程风格几乎总是一个好主意,例如复制和验证参数和返回值
这种行为在Java5/6中仍然存在吗
您可以使用该工具确定二进制文件的公开内容和方式。package demo;
public class SyntheticAccessors {
private boolean encapsulatedThing;
class Inner {
void doSomething() {
encapsulatedThing = true;
}
}
}
Compiled from "SyntheticAccessors.java"
public class demo.SyntheticAccessors extends java.lang.Object{
public demo.SyntheticAccessors();
static void access$0(demo.SyntheticAccessors, boolean);
}
public class InnerExample {
private int field = 42;
private class InnerClass {
public int getField () { return field; };
}
private InnerClass getInner () {
return new InnerClass();
}
public static void main (String...args) {
System.out.println(new InnerExample().getInner().getField());
}
}
$ javap -classpath bin -private InnerExample
Compiled from "InnerExample.java"
public class InnerExample extends java.lang.Object{
private int field;
public InnerExample();
private InnerExample$InnerClass getInner();
public static void main(java.lang.String[]);
static int access$000(InnerExample);
}
$ javap -classpath bin -c -private InnerExample
static int access$000(InnerExample);
Code:
0: aload_0
1: getfield #1; //Field field:I
4: ireturn
import java.lang.reflect.*;
public class InnerThief {
public static void main (String...args) throws Exception {
for (Method me : InnerExample.class.getDeclaredMethods()){
System.out.println(me);
System.out.printf("%08x\n",me.getModifiers());
}
System.out.println(InnerExample.access$000(new InnerExample()));
}
}