其中,权限的名称就是抽象了的敏感信息;权限的操作就是对信息的处理。如果把权限的名称和权限的操作结合起来,就可以定义特定的权限了。比如,下面的例子就定义了对于文件目录“/home/myhome”的读操作。
```
permission java.io.FilePermission "/home/myhome", "read";
```
**第二件事情,就是定义权限的主体**。也就是说,要明确权限可以分派给谁。在JDK中,权限的主体通过java.security.Principal接口来定义。Principal接口可以用来表述个人,组织或者虚拟的账户。比如,com.sun.security.auth.UnixPrincipal可以用来表述Unix的用户。
```
Principal com.sun.security.auth.UnixPrincipal "duke"
```
**第三件事情,就是要定义权限的归属**。也就是说,有了权限的定义和权限主体的定义,我们就可以分配权限了。下面的例子,就是把对“/home/duke”的读写操作权限,赋予给了Unix用户duke。
```
grant Principal com.sun.security.auth.UnixPrincipal "duke" {
permission java.io.FilePermission "/home/duke", "read, write";
};
```
上述的三个例子,就是Java权限管理策略文件的最基本概念。更详细的内容,权限管理策略文件的语法以及API的调用,请参阅有关Java的规范。
敏感信息经过授权才可以使用,这看起来是一个漂亮的解决方案。我们是不是可以高枕无忧了? 这还远远不够。这套解决方案能够实施下去,还是有很多挑战的。比如说,敏感信息的操作处理过程,也会造成信息的非授权泄漏。
## 特殊信息,特殊处理
现代信息系统资源,一般都是多用户共享,多应用共享,跨边界合作的,比如内存、硬盘、中央处理器和互联网。而敏感信息是不能共享的,如何在共享的资源内,不留下敏感信息的踪迹?这是一个让人头疼的问题。
比如说吧,要使用敏感信息,就要把敏感信息载入内存,如果发生内存溢出攻击,攻击者就可以绕过权限管理,获取或者修改敏感信息,甚至可以修改对敏感信息的操作。
**针对敏感信息的操作,需要特殊的处理和特殊的技术。**
敏感信息的无意识泄露是一种比较常见的敏感信息泄露事件。比如说,把敏感信息泄露在抛出异常里,应用日志里,或者序列化对象里。
比如说,如果一个文件不存在,一般的代码实现会倾向于抛出java.io.FileNotFoundException异常。为了使异常信息更加直观,我们常常把文件路径包含在异常的消息里,或者记录在应用日志里。
```
java.io.FileNotFoundException: /home/duke/.ssh was not found
```
这个异常信息有可能绕过权限管理,传达给未授权用户。这个信息里包含了三个重要的敏感信息:
当前用户名是“duke”;
当前用户没有配置SSH协议;
有可能获知特定文件是否存在。
当实现一个文件管理类时,我们可能会习惯于面向对象的机制。比如,给定一个文件的路径,代码就执行一定的读写操作。至于该文件路径是什么,包含什么内容,是否有敏感信息,都不在该类的考虑范围之内。实现这个类时,我们更可能倾向于使用直观友好的异常信息,而不会意识到这些**异常信息可能携带敏感数据,导致敏感数据通过异常信息泄露**。
**这和我们一般的面向对象的编程习惯是不符合的,这就要求我们特别小心**。从实现者的角度出发,抛出的异常信息尽量做到不包含可能的敏感信息;从调用者的角度出发,截获的异常信息在传递到上层调用之前,如果有必要,需要做净化处理。比如,把上述的java.io.FileNotFoundException转化成更普通的java.io.IOException。
```
java.io.IOException: An IOException was caught!
```
下面的异常堆栈是不是可以接受呢?
```
java.io.IOException: An IOException was caught!
at com.example.myapp.MyHTTPSerer.myMethod(MyHTTPSerer.java:250)
...
Caused by java.io.FileNotFoundException: /home/duke/.ssh was not found
at com.example.myapp.MyFileStream.open(MyFileStream.java:249)
```
这个异常堆栈的“Caused by”部分泄露了同样的敏感信息。所以,**在做异常信息净化处理时,可能还需要避免传递捕获异常的堆栈**。特别是如果调用结果直接面向最终用户,就应当尽量避免使用异常堆栈。比如说,在HTML页面中显示异常信息和异常堆栈,就容易出问题。
在后面的文章中,我们还会讨论敏感信息及时归零的话题。这也是对于高度敏感信息的一种特殊处理方式。
## 小结
通过对这个案例的讨论,我想和你分享下面两点个人看法: