Java 我们能利用类型系统使程序更安全吗?

Java 我们能利用类型系统使程序更安全吗?,java,c++,security,types,Java,C++,Security,Types,这个问题的灵感来自Joel的“让错误的代码看起来是错误的” 有时,您可以使用类型在接口之外的对象上强制语义。例如,Java接口Serializable实际上并不定义方法,但对象实现Serializable的事实说明了应该如何使用它 我们可以在Java中使用UnsafeString和SafeString接口/子类吗?这些接口/子类的使用方式与Joel的匈牙利符号和Java的Serializable基本相同,这样它就不会看起来很糟糕——不会编译了 这在Java/C/C++中是可行的,还是类型系统太

这个问题的灵感来自Joel的“让错误的代码看起来是错误的”

有时,您可以使用类型在接口之外的对象上强制语义。例如,Java接口Serializable实际上并不定义方法,但对象实现Serializable的事实说明了应该如何使用它

我们可以在Java中使用UnsafeString和SafeString接口/子类吗?这些接口/子类的使用方式与Joel的匈牙利符号和Java的Serializable基本相同,这样它就不会看起来很糟糕——不会编译了

这在Java/C/C++中是可行的,还是类型系统太弱或太动态


此外,除了输入清理之外,还有哪些安全功能可以用这种方式实现?

在Java中不能有一个不安全的String子类,因为


一般来说,您不能在源代码级别提供任何类型的安全性—如果您想要防止恶意代码,您必须在二进制级别(例如Java字节码)上这样做。这就是为什么在C++中不能将private/protected用作安全机制的原因:可以通过指针操作绕过它。

是的,您可以做这样的事情。我不知道java,但是C++中没有习惯,没有支持,所以你必须做一些手工工作。这在其他一些语言中是习惯性的,例如Ada,它有一个typedef的等价物,它引入了一个不能隐式转换为原始类型的新类型(这个新类型“继承”了它所创建的类型的一些基本操作,所以它仍然有用)


顺便说一句,一般来说,继承不是引入新类型的好方法,因为即使一种方式没有隐式转换,另一种方式也有隐式转换。

在Ada中,您可以在开箱即用的情况下完成一定数量的转换。例如,您可以使整数类型彼此无法实现互操作,并且Ada枚举与任何整数类型都不兼容。您仍然可以在它们之间进行转换,但必须显式地进行转换,这会引起对您正在做的事情的注意

你可以在当今C++中做同样的事情,但是你必须把所有的整数和枚举都包在类中,这对于那些应该是简单的(或者更好的,默认的做事方式)来说是太多的工作了。

我知道C++的下一个版本至少要解决枚举问题。

< p>类型系统已经强制执行了大量的安全特性。这就是它的本质

举一个非常简单的例子,它阻止您将浮点值视为int。这是安全性的一个方面——它保证您正在处理的类型将按照预期的方式运行。它保证只对字符串调用字符串方法。例如,程序集没有这种保护措施

类型系统的工作还包括确保不在类上调用私有函数。这是另一个安全特性

Java的类型系统太贫乏,无法有效地实施许多有趣的约束,但在许多其他语言(包括C++)中,类型系统可以用于实施范围更广的规则

在C++中,模板元编程为您提供了很多禁止“坏”代码的工具。例如:

class myclass : boost::noncopyable {
 ...
};
在编译时强制类不能被复制。以下内容将产生编译错误:

myclass m;
myclass m2(m); // copy construction isn't allowed
myclass m3;
m3 = m; // assignment also not allowed
同样,我们可以在编译时确保模板函数只在满足某些条件的类型上被调用(例如,它们必须是随机访问迭代器,而双线性迭代器是不允许的,或者它们必须是POD类型,或者它们不能是任何类型的整数类型(char、short、int、long),但所有其他类型都应该是合法的

C++中的模板元编程的一个教科书实例实现了一个计算物理单元的库,它允许你将一个“米”类型的值与同一类型的另一个值相乘,并自动确定结果必须是“平方米”类型,或者将“英里”类型的值与“小时”类型的值进行划分。然后得到一个“英里每小时”的单位

同样,一种安全功能可以防止您的类型混淆和意外混淆单位。如果您计算一个值并尝试将其分配给错误的类型,则会出现编译错误。尝试将(比如)升除以
米^2
并将结果分配给(比如)千克,将导致编译错误


大部分都需要一些人工的工作来建立,但是语言可以提供你需要的工具来基本上建立你想要的类型检查。一些可以直接在语言中更好地支持,但是更创造性的检查无论如何都必须手动实现。C++中的< /P> < P> >,我想你可以使用<代码>类型化。ef为基元类型创建同义词。同义词可能暗示该变量的内容,取代匈牙利符号的功能


Intellisense将报告您在声明过程中使用的同义词,因此,如果您不喜欢使用实际的匈牙利语,它确实可以避免您滚动(或使用Go To Definition)。

我猜您在考虑Perl的“污染”分析


在Java中,应该可以使用自定义注释和注释处理器来实现这一点。但这并不一定容易。

我们不是在防范恶意Java代码。我们是在防范恶意输入(例如跨站点脚本)使用编译器来清除“气味”而不是Joel的匈牙利方法是这里的愿望。但是,在最后的类部分,这是一个很好的调用。不过,这只是一个障碍,而不是一个僵局。播客58()也讨论了这一点它基本上就是一个类型系统。没有类型系统,任何变量都可以像其他变量一样处理。你可以访问