首頁  >  文章  >  運維  >  Java應用程式的安全沙箱機制是什麼

Java應用程式的安全沙箱機制是什麼

PHPz
PHPz轉載
2023-05-16 18:26:22901瀏覽

如果你經常閱讀源碼,你會發現Java 的源碼中到處都有類似於下面這一段代碼

<code class="hljs java">class File {<br>  // 判断一个磁盘文件是否存在<br>  public boolean exists() {<br>    SecurityManager security = System.getSecurityManager();<br>    if (security != null) {<br>      security.checkRead(path);<br>    }<br>    ...<br>  }<br>}<br></code>


這明顯是一個安全檢查代碼,檢查的是你是否有訪問磁碟路徑的權限,為什麼Java 語言需要這樣的安全檢查程式碼呢?我們再看看客戶端套接字的connect 函數原始碼,它需要檢查使用者是否有connect 某個網路位址的權限

<code class="hljs cs">class Socket {<br>  public void connect(SocketAddress endpoint, int timeout) {<br>    ...<br>    SecurityManager security = System.getSecurityManager();<br>    if (security != null) {<br>       if (epoint.isUnresolved())<br>          security.checkConnect(epoint.getHostName(), port);<br>       else<br>          security.checkConnect(addr.getHostAddress(), port);<br>       }<br>    }<br>    ...<br>  }<br>}<br></code>


再看服務端套接字的來源碼,它會檢查連接埠的監聽權限

<code class="hljs cs">class ServerSocket {<br>  public void bind(SocketAddress endpoint, int backlog) {<br>    ...<br>    SecurityManager security = System.getSecurityManager();<br>    if (security != null)<br>       security.checkListen(epoint.getPort());<br>    ...<br>  }<br>}<br></code>


似乎所有和IO 操作有關的方法呼叫都需要進行安全性檢查。看起來IO操作相關的權限檢查是可理解的,使用者程序不能隨意存取所有的IO資源。但連環境變數都不讓隨意讀,而且限制的還不是所有環境變量,而是某個具體的環境變量,這安全檢查是不是有點過了?

<code class="hljs cs">class System {<br>  public static String getenv(String name) {<br>    SecurityManager sm = getSecurityManager();<br>    if (sm != null) {<br>       sm.checkPermission(new RuntimePermission("getenv."+name));<br>    }<br>    return ProcessEnvironment.getenv(name);<br>  }<br>}<br></code>


這是因為Java 的安全檢查管理器和作業系統的權限檢查不是一個概念,Java 編寫的不只是服務端應用程序,它還可以作為客戶端跑在瀏覽器上(Applet),它也可以以app 的形式跑在手機上(J2ME),針對不同的平台JVM 會使用不同的安全策略。通常情況下,針對 Applet 的限制非常嚴格,一般不允許 Applet 操作本機檔案。執行具體 IO 操作前,一旦 Java 的安全性檢查通過,作業系統仍會進行權限檢查。

我們平常在本地運行java 程式時通常都不會預設打開安全檢查器,需要執行jvm 參數才會打開

<code class="hljs shell">$ java -Djava.security.manager xxx<br>$ java -Djava.security.manager -DDjava.security.policy="${policypath}"<br></code>


因為安全限制條件可以定制,所以還需要提供具體的安全性原則檔案路徑,預設的策略檔案路徑是JAVA_HOME/jre/lib/security/java.policy,下面讓我們來看看這個檔案裡都寫了些什麼

<code class="hljs dart">// 内置扩展库授权规则<br>// 表示 JAVA_HOME/jre/lib/ext/ 目录下的类库可以全权访问任意资源<br>// 包含 javax.swing.*, javax.xml.*, javax.crypto.* 等等<br>grant codeBase "file:${{java.ext.dirs}}/*" {<br> permission java.security.AllPermission;<br>};<br><br>// 其它类库授权规则<br>grant {<br> // 允许线程调用自己的 stop 方法自杀<br> permission java.lang.RuntimePermission "stopThread";<br> // 允许程序监听 localhost 的随机可用端口,不允许随意订制端口<br> permission java.net.SocketPermission "localhost:0", "listen";<br> // 限制获取系统属性,下面一系列的配置都是只允许读部分内置属性<br> permission java.util.PropertyPermission "java.version", "read";<br> permission java.util.PropertyPermission "java.vendor", "read";<br> permission java.util.PropertyPermission "java.vendor.url", "read";<br> permission java.util.PropertyPermission "java.class.version", "read";<br> permission java.util.PropertyPermission "os.name", "read";<br> permission java.util.PropertyPermission "os.version", "read";<br> permission java.util.PropertyPermission "os.arch", "read";<br> permission java.util.PropertyPermission "file.separator", "read";<br> permission java.util.PropertyPermission "path.separator", "read";<br> permission java.util.PropertyPermission "line.separator", "read";<br> permission java.util.PropertyPermission "java.specification.version", "read";<br> permission java.util.PropertyPermission "java.specification.vendor", "read";<br> permission java.util.PropertyPermission "java.specification.name", "read";<br> permission java.util.PropertyPermission "java.vm.specification.version", "read";<br> permission java.util.PropertyPermission "java.vm.specification.vendor", "read";<br> permission java.util.PropertyPermission "java.vm.specification.name", "read";<br> permission java.util.PropertyPermission "java.vm.version", "read";<br> permission java.util.PropertyPermission "java.vm.vendor", "read";<br> permission java.util.PropertyPermission "java.vm.name", "read";<br>};<br></code>


grant 如果提供了codeBase 參數就是針對特定的類別庫來配置權限規則,如果沒有指定codeBase 就是針對所有其它類別庫配置的規則。

安全檢查沒有通過,那就會拋出 java.security.AccessControlException 例外。即使通過了安全性檢查,作業系統的權限檢查也有可能失敗,此時將會拋出其他類型的例外。

如果按照上面所配置的規則,使用預設安全性策略的 JVM 將無法存取本機文件,因為授權規則使用的是白名單。如果需要存取本機文件,可以增加下面的規則

<code class="hljs lua">permission java.io.FilePermission "/etc/passwd", "read";<br>permission java.io.FilePermission "/etc/shadow", "read,write";<br>permission java.io.FilePermission "/xyz", "read,write,delete";<br>// 允许读所有文件<br>permission java.io.FilePermission "*", "read";<br></code>


Permission 的設定參數剛好對應了它的建構器參數

<code class="hljs java">public FilePermission(String path, String actions) {<br>  super(path);<br>  init(getMask(actions));<br>}<br></code>


Java 預設安全性規則分為幾大模組,每個模組都有各自的設定參數

Java應用程式的安全沙箱機制是什麼

其中AllPermission 表示開啟所有權限。還有一個不速之客 HibernatePermission,它並不是內建的權限模組,它是 Hibernate 框架為自己訂製的,這意味著安全規則是支援自訂擴充功能的。要擴充很容易,只需編寫一個 Permission 子類,並實作其四個抽象方法。

<code class="hljs java">abstract class Permission {<br>  // 权限名称,对于文件来说就是文件名,对于套接字来说就是套接字地址<br>  // 它的意义是子类可定制的<br>  private String name;<br>  // 当前权限对象是否隐含了 other 权限<br>  // 比如 AllPermission 的这个方法总是返回 true<br>  public abstract boolean implies(Permission other);<br>  // equals 和 hashcode 用于权限比较<br>  public abstract boolean equals(Object obj);<br>  public abstract int hashCode();<br>  // 权限选项 read,write,xxx<br>  public abstract String getActions();<br>}<br><br>class CustomPermission extends Permission {<br>  private String actions;<br>  CustomPermission(string name, string actions) {<br>    super(name)<br>    this.actions = actions;<br>  }<br>  ...<br>}<br></code>


JVM 啟動時會將profile 裡面定義的權限規則載入到權限池中,使用者程式在特定的API 方法中使用權限池來判斷是否包含呼叫這個API 的權限,最終會落實到呼叫權限池中每一個權限物件的implies 方法來判斷是否具備指定權限。

<code class="hljs cs">class CustomAPI {<br>  public void someMethod() {<br>    SecurityManager sec = System.getSecurityManager();<br>    if(sec != null) {<br>      sec.CheckPermission(new CustomPermission("xname", "xactions"));<br>    }<br>    ...<br>  }<br>}<br></code>


啟用安全性檢查,將會降低程式的執行效率,如果profile 裡面定義的權限規則特別多,那麼檢查效率就會很慢,使用時注意安全檢查要省點使用。

沙箱的安全檢查點非常多,以下列舉一些常見的場景

  1. #檔案操作

  2. 套接字操作

  3. 執行緒與執行緒組

  4. 類別載入器控制

  5. 反射控制

  6. 執行緒堆疊資訊取得

  7. 網路代理控制

  8. Cookie 讀寫控制

如果你的服務端程式開啟了安全性檢查,就需要在policy 設定檔裡開啟很多安全性設置,非常繁瑣,而且設定多了,檢查的效能也會產生一定損耗。這一點有點類似 Android 的應用權限設置,在每個 Android 應用程式的設定檔裡都需要羅列出一系列應用子權限。不過用 Java 來寫服務端程式似乎開啟安全性檢查沒有任何必要。

以上是Java應用程式的安全沙箱機制是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除