Google App Engine for Java是可以在Google托管服务器基础架构上托管和运行用户Web应用程序。出于安全原因,这些应用程序在沙盒环境中执行。
沙箱本身由两层组成。第一层是GAE Java沙箱,它建立在底层Java SE软件之上。第二层是本机OS沙箱,它限制了操作系统对用户应用程序和GAE环境本身的暴露。
标准Java SE安全沙箱以及GAE沙盒层的存在对GAE环境中执行的用户应用程序强制实施了若干限制。
默认情况下,用户应用程序无法访问基础本机OS的文件系统。用户代码只对其唯一的应用程序部署目录及其所有子目录具有只读访问权限。用户应用程序无法将任何数据写入文件系统。他们需要使用App Engine数据存储区API进行任何持久数据存储
网络套接字仅适用于GAE付费应用程序,只能创建出站,客户端(非监听)TCP或UDP套接字,不能绑定到特定地址或端口
用户应用程序是Web应用程序,因此它们通过Servlet API或JSP文件处理Web请求。用户代码通常在关联的HTTP请求时生成。 GAE确保在完成请求处理后终止与给定HTTP请求关联的所有线程。同时在处理HTTP请求后没有用户代码被执行。这其中包括各种系统Java处理程序和终结程序。虽然GAE中提供了对所谓的后台线程和cron任务的支持,但它们并未实现为经典后台Java线程。
大多数java.lang.System API不适用于用户应用程序。因此,用户代码无法隐式触发GC操作。但GAE使用户代码可以创建任意类加载器。因此,用户应用程序可以成功定义和创建java.lang.ClassLoader类的子类实例来实现自定义类的加载逻辑。类加载器可以为JVM提供类定义及其权限(保护域和权限)。GAE允许对应用程序自己的类(由应用程序类加载器或自定义的用户定义的类加载器定义的类)进行完全和不受限制的Reflection API访问。
为了最大限度地降低JRE中存在的安全漏洞带来的风险,GAE采用了JRE Class White List的概念。它的目标是限制用户代码可以访问的JRE类集。只有在环境中允许所请求的类时,任意类加载或链接才会成功(它存在于被视为安全JRE类的列表中的JRE类白名单)。
GAE Java Runtime沙箱在native和Java类级别实现。其依赖于两个通信通道来服务和处理特定的RPC请求。两个通道都是沙盒启动过程的一部分。native Java Runtime层依赖于C1通道。非原生层使用C2通道。
GAE Runtime实现了虚拟文件系统给任意文件访问,并再native层实现拦截与代理(LibcProxy和FDProxy组件)。通过GAE的代理库调用实现C1通信通道将它们分派给适当的RPC服务。
在GAE中,用户应用程序加载的所有类都需要在定义JVM中的给定类之前执行强制验证步骤(扫描)。扫描是通过UserClassLoader类的代码及其特定的findClass方法进行的。类扫描构成了GAE Java沙箱的基本安全机制。类加载器,反射API,JRE类白名单几个关键GAE安全概念的实现依赖于它。检查过程本身依赖于类文件的静态分析,使用ASM(Java字节码操作和分析框架)实现类扫描。如果给定的Class文件不满足GAE沙箱的某些安全要求(即无效的子类化),则类扫描可能引发异常。如果已完成,则输入的Class字节将被复制到输出流而不进行任何修改,或者根据特定规则进行转换。
GAE实现了一种允许任意修改或完全拦截JRE类的机制。 API注入机制使得在调用另一个方法之前调用给定方法成为可能。 API拦截允许调用给定方法来代替另一个方法。拦截API可以应用于方法,字段和构造函数。 Interjection API仅支持方法。 GAE Class Sweeper对检查类的代码应用适当的转换,以实现API插入和拦截功能。如果用户代码中引用的给定类具有镜像,则对它的每个引用都将替换为对该镜像的引用。类似地,在镜像类中具有相应实现(定义)的类的方法(字段)的实例调用被镜像方法(字段)的静态调用(访问操作)替换。 截至2014年10月,GAE针对160个JRE类实施了API拦截。 API Interjection仅针对4个类进行。
由于拦截机制,本地GAE环境难以完全复现Google的生产环境,在本地GAE环境中开发和测试的所有POC,在本地运行良好,但其中许多在生产环境中失败了。
GAE存根类包含虚拟方法和初始化程序,除了在调用时抛出异常之外没有太多作用。
GAE Java运行时创建了几个Class Loader名称空间,它们在用户,运行时和系统代码之间提供了自然的隔离。用户应用程序代码加载始终由com.google.apphosting.runtime.security.UserClassLoader类的实例处理。此类加载器也设置为当前Thread的上下文类加载器。 UserClassLoader命名空间始终是Class Sweeping的主题。这在类加载器级别为GAE沙箱层形成安全边界。UserClassLoader还依赖于两个额外的类加载器来进行类加载。 com.google.apphosting.runtime.security.RuntimeClassLoader类的实例用于加载GAE Java Runtime实现类。还有一个PrivilegedClassLoader类的实例,它是UserClassLoader的一个内部类。它处理实现Class Sweeper的API Interjection和Interception层的类(所有拦截/插入的类定义)。