我们可以利用类型系统来使程序更安全吗?

时间:2009-07-31 18:37:50

标签: java c++ security types

这个问题的灵感来自乔尔的“使错误的代码看错了”

http://www.joelonsoftware.com/articles/Wrong.html

有时您可以使用类型来强制超出其接口的对象的语义。例如,Java接口Serializable实际上并没有定义方法,但是一个对象实现Serializable的事实说明了应该如何使用它。

我们可以在Java中使用UnsafeString和SafeString接口/子类,这些接口/子类的使用方式与Joel的匈牙利符号和Java的Serializable大致相同,因此它不会看起来很糟糕 - 它不能编译吗?

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

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

6 个答案:

答案 0 :(得分:3)

类型系统已经强制执行大量此类安全功能。这基本上就是

对于一个非常简单的示例,它会阻止您将float视为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 ++中模板元编程的教科书示例实现了用于计算物理单元的库。它允许您将“米”类型的值与另一个相同类型的值相乘,并自动确定结果必须是“平方米”类型。或者将“mile”类型的值除以“hour”类型的值,并获得“每小时英里数”类型的单位。

同样,一项安全功能可以防止您将类型混淆并意外地让您的单位混乱。如果计算值并尝试将其分配给错误的类型,则会出现编译错误。试图按meters^2除以升,并将结果分配给公斤值,这将导致编译错误。

当然,大多数情况下需要手动设置一些工作,但语言为您提供了基本构建所需类型检查所需的工具。其中一些可以直接在语言中得到更好的支持,但在任何情况下都必须手动实施更有创意的检查。

答案 1 :(得分:1)

是的,你可以做这样的事情。我不了解Java,但在C ++中它并不习惯,也没有对此的支持,所以你必须做一些手工操作。习惯于其他一些语言,例如Ada,它具有相当于typedef的类型,它引入了一种不能隐式转换为orignal的新类型(这种新类型“继承”了一些基本操作。创建,所以它保持有用。)

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

答案 2 :(得分:0)

你可以在Ada中开箱即用。例如,您可以创建不能互相影响的整数类型,并且Ada枚举与任何整数类型都不兼容。你仍然可以在它们之间进行转换,但你必须明确这样做,这会引起你对你正在做的事情的注意。

你可以对现今的C ++做同样的事情,但是你必须将所有的整数和枚举包装在类中,这对于一些应该简单(或者更好,默认方式)的东西来说太过分了。做事。)

我理解下一版本的C ++至少会解决枚举问题。

答案 3 :(得分:0)

在C ++中,我想你可以使用typedef来创建基本类型的同义词。你的同义词可能暗示了该变量的内容,取代了匈牙利语应用程序的功能。

Intellisense将报告您在声明期间使用的同义词,因此如果您不喜欢使用实际的匈牙利语,它会使您无法滚动(或使用“转到定义”)。

答案 4 :(得分:0)

我猜你正在考虑Perl的“污点”分析。

在Java中,应该可以使用自定义注释和注释处理器来实现它。虽然不一定容易。

答案 5 :(得分:-1)

由于java.lang.String is final,你不能在Java中拥有String的UnsafeString子类。

通常,您无法在源级别提供任何类型的安全性 - 如果要防止恶意代码,则必须在二进制级别(例如Java字节码)上执行此操作。这就是为什么private / protected不能用作C ++中的安全机制的原因:可以通过指针操作绕过它。