分散式運算與時間和狀態相關。也就是說,為了使多個元件進行通訊,必須共用狀態,並且這一切都需要時間。
大多數的程式設計師將他們的工作擬人化。他們想採用一種控制執行緒來執行整個程式,就像他們必須自己完成這項工作一樣。但是,現代的電腦可以非常快速地切換工作,並且在多核心多 CPU 或分散式系統中,兩個事件可能恰好同時發生。瑕疵急於填補程式設計師在程式執行模型與實際情況之間的差距。這些瑕疵與執行緒、處理序、時間和資訊之間的意外互動有關。這些互動透過共用狀態發生:信號、變數、檔案系統,以及基本上任何可以儲存資訊的項目。
HttpSession
屬性儲存,會破壞應用程式的可靠性。HttpSession
物件,所以當一個 JVM 不可用時,另一個 JVM 可以在不中斷應用程式流程的情況下接替它。Serializable
介面。
public class DataGlob {
String globName;
String globValue;
public void addToSession(HttpSession session) {
session.setAttribute("glob", this);
}
}
block.timestamp
或 block.number
做為時間的 Proxy。block.timestamp
或 block.number
相關的值通常由開發人員用來觸發與時間相關的事件,但是,這些值通常給人一種用起來通常不安全的時間感。block.timestamp
充其量是不可靠的,在最壞的情況下,惡意挖礦者可以更改其區塊的時間,只要他們認為這樣做有好處。block.number
,即使可以預測區塊之間的時間 (大約14秒),區塊時間也不是恆定的,並且可能會根據網路活動而異。如此一來,對於與時間相關的計算來說,block.number
並不可靠。block.number
,在一定時間過後才會解鎖資金。
function withdraw() public {
require(users[msg.sender].amount > 0, 'no amount locked');
require(block.number >= users[msg.sender].unlockBlock, 'lock period not over');
uint amount = users[msg.sender].amount;
users[msg.sender].amount = 0;
(bool success, ) = msg.sender.call.value(amount)("");
require(success, 'transfer failed');
}
...
var authenticated = true;
...
database_connect.query('SELECT * FROM users WHERE name == ? AND password = ? LIMIT 1', userNameFromUser, passwordFromUser, function(err, results){
if (!err && results.length > 0){
authenticated = true;
}else{
authenticated = false;
}
});
if (authenticated){
//do something privileged stuff
authenticatedActions();
}else{
sendUnathenticatedMessage();
}
true
,否則會設為 false
。很遺憾,由於回撥遭到 IO 封鎖,因此將會異步執行, 並可能在對 if (authenticated)
進行檢查後執行,而由於預設值為 true,因此無論使用者是否確實得到驗證,回撥都將進入 if 陳述式。
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/download/" + "app.apk")), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
setuid root
的程式。程式代表無權限使用者執行了特定的檔案操作,並使用存取檢查來確保它不使用其根權限執行目前使用者不應該執行的操作。程式使用 access()
系統呼叫來檢查在程式開啟檔案和執行必要操作之前,執行程式的使用者是否具有權限去存取這些指定的檔案。
if (!access(file,W_OK)) {
f = fopen(file,"w+");
operate(f);
...
}
else {
fprintf(stderr,"Unable to open file %s.\n",file);
}
access()
呼叫的運作方式在意料之中,而且,如果執行程式的使用者具有必要的權限來編輯檔案,那麼就會回傳 0
,其他情況則會回傳-1。無論怎樣,因為 access()
和 fopen()
都是對檔案名稱進行操作,而不是對檔案控制碼進行操作,所以當 file
變數傳送到 fopen()
的時候,就不能保證這個變數仍然能夠像傳送到 access()
的時候那樣參照磁碟上相同的檔案。如果攻擊者在 access()
呼叫之後,用指向不同檔案的一個象徵連結來取代 file
,程式就會使用它的根權限對檔進行操作,即使這個檔案攻擊者在其他情況下是無法篡改的。藉由欺騙程式去執行其他情況下不被允許的操作,攻擊者就能取得權限的提高。root
權限,因而沒有受到程式的限制。如果應用程式有能力執行攻擊者在其他情況下不被允許的任何操作,那麼這個程式就是一個可能的攻擊目標。
fd = creat(FILE, 0644); /* Create file */
if (fd == -1)
return;
if (chown(FILE, UID, -1) < 0) { /* Change file owner */
...
}
chown()
呼叫所操作的檔案與對 creat()
的呼叫所建立的檔案相同,但實際上未必如此。由於 chown()
是針對檔案名稱 (而非檔案控制碼) 進行操作,因此攻擊者可能會使用並非由攻擊者所擁有的檔案連結來取代檔案。隨後,對 chown()
的呼叫會為攻擊者提供所連結檔案的擁有權。CBL_CHECK_FILE_EXIST
常式,以在建立檔案之前先檢查檔案是否存在,並執行必要的操作。
CALL "CBL_CHECK_FILE_EXIST" USING
filename
file-details
RETURNING status-code
END-CALL
IF status-code NOT = 0
MOVE 3 to access-mode
MOVE 0 to deny-mode
MOVE 0 to device
CALL "CBL_CREATE_FILE" USING
filename
access-mode
deny-mode
device
file-handle
RETURNING status-code
END-CALL
END-IF
CBL_CHECK_FILE_EXIST
呼叫的運作方式在意料之中,並傳回一個非零值,表示該檔案不存在。不過,因為 CBL_CHECK_FILE_EXIST
和 CBL_CREATE_FILE
都是對檔案名稱進行操作,而不是對檔案控制碼進行操作,所以當 filename
變數傳遞到 CBL_CREATE_FILE
的時候,就不能保證這個變數仍然能夠像傳遞到 CBL_CHECK_FILE_EXIST
的時候那樣參照磁碟上相同的檔案。如果攻擊者在 CBL_CHECK_FILE_EXIST
呼叫後建立 filename
,CBL_CREATE_FILE
的呼叫將會失敗,進而導致程式認為該檔案是空的,但實際上它包含由攻擊者控制的資料。root
權限的程式,以代表無權限使用者執行特定檔案操作,並使用存取測試來確保它沒有使用其根權限來執行操作,這種權限對目前使用者來說在其他情況下是無法取得的。藉由欺騙程式去執行其他情況下不被允許的操作,攻擊者就可能取得提升的權限。java.text.Format
中的 parse()
和 format()
方法有設計上的缺陷,可能導致使用者看見其他使用者的資料。java.text.Format
中的 parse()
和 format()
方法有 race condition,可能導致使用者看見其他使用者的資料。
public class Common {
private static SimpleDateFormat dateFormat;
...
public String format(Date date) {
return dateFormat.format(date);
}
...
final OtherClass dateFormatAccess=new OtherClass();
...
public void function_running_in_thread1(){
System.out.println("Time in thread 1 should be 12/31/69 4:00 PM, found: "+ dateFormatAccess.format(new Date(0)));
}
public void function_running_in_thread2(){
System.out.println("Time in thread 2 should be around 12/29/09 6:26 AM, found: "+ dateFormatAccess.format(new Date(System.currentTimeMillis())));
}
}
format()
時發生 race condition,第一個執行緒的日期會在第二個執行緒的輸出中顯示。