2013-03-07 77 views
14

我是Java新手,在學習時發現String是不可變的。當我讀到背後的原因時,出現了一些原因,例如性能提升,因爲它的值不能被修改,並且它可以被多個線程共享。這些理由我明白。
但我不明白它與安全有關。 String如何在Java安全性中不可變?Java字符串如何不可變增加安全性?

請幫我理解。提前致謝。

+2

它說它有助於安全嗎?的 – ivant 2013-03-07 15:24:03

+0

可能重複[Java繼承,如何延伸的一類效果的實際類](http://stackoverflow.com/questions/15165619/java-inheritance-how-does-a-extending-a-class-effect- 「實際」類) – jtahlborn 2013-03-07 15:33:19

回答

15

一個非常普遍的做法書面類庫被存儲傳遞到你的API,比如參數,在構造函數,像這樣:

public class MyApi { 
    final String myUrl; 
    public MyApi(String urlString) { 
     // Verify that urlString points to an approved server 
     if (!checkApprovedUrl(urlString)) throw new IllegalArgumentException(); 
     myUrl = urlString; 
    } 
} 

String可變,這會導致一個微妙的利用:攻擊者會傳遞一個好的URL,等待幾微秒,然後將URL設置爲指向攻擊站點。

由於沒有存儲複製是一個相當普遍的做法,因爲字符串是最常用的數據類型中,留下串可變將開闢還未被寫入開放的一個嚴重的安全問題,許多API。使字符串不可變將關閉所有API的特定安全漏洞,包括那些尚未寫入的API。

+1

(「部分」)可變性的一個很好的例子是File。本質上它只是包裝一個'String'。然而,有很多情況下它已被用於安全檢查。惡意的子類可以在檢查和使用之間改變(TOCTOU/TOC2TOU漏洞)。 – 2013-03-07 17:17:49

+1

我不知道微妙的漏洞是如何完成的,但假設該方法會被另一個線程以某種方式攔截。基本上,因爲如果使用urlString「ABC」調用MyApi構造函數時,String是不可變的,則內容不能從構造函數外部更改。如果它不是不可變的,則可以通過調用urlString =「someMaliciousUrl」在另一個線程上進行變異。在checkApprovedUrl調用之後。這種理解是否正確? – Mercury 2016-04-30 12:22:33

+0

@Mercury是的,這是對上述攻擊的正確理解。 – dasblinkenlight 2016-04-30 12:25:58

0

字符串是,你不能改變對象本身不變的手段,但你可以改變課程的參考。當你調用(例如)a =「ty」時,實際上是將a的引用更改爲由字符串字面值「ty」創建的新對象。更改對象表示使用它的方法來改變它的領域之一,例如:

Foo x = new Foo("the field"); 
x.setField("a new field"); 
System.out.println(x.getField()); // prints "a new field" 

而不可變類(聲明爲final),例如字符串,你不能改變當前的字符串,但您可以返回一個新的String,即:

String s = "some text"; 
s.substring(0,4); 
System.out.println(s); // still printing "some text" 
String a = s.substring(0,4); 
System.out.println(a); // prints "some" 
+4

「最終」並不意味着它是不可變的。對於類,它意味着你不能繼承它。 – ivant 2013-03-07 15:25:56

+0

爲不可變的,你必須要最終使你的子類不會破壞不變性 – topcat3 2013-03-07 15:28:14

+0

,可能是這樣,但它是不夠的,聲明它最終使其一成不變的。 – ivant 2013-03-07 15:29:39

3

不可改變的字符串是必需的安全管理器的概念工作。 dasbklinkenlight已經在他的回答中處於正確的軌道上,但可變字符串將完全打破沙箱概念。

例如,當你做一個new FileInputStream("foo");讀取文件時,API的實現將在內部等等做:

  • 調用安全管理器的checkRead方法與「富」作爲參數,並拋出如有異常檢查失敗
  • 使用操作系統調用實際打開該文件,如果安全檢查合格

如果調用就能夠修改這兩個步驟之間的字符串,安全檢查可以爲一個成功文件,而實際上將打開一個不同的文件。

+0

不知道如果我理解正確,我有一個疑問,因爲Java通過價值安全檢查發生了foo只有foo將被打開 – 2017-11-25 10:20:16