2010年2月23日 星期二

Directory traversal與 ESAPI提供之RandomAccessReferenceMap


Directory traversal發生於開發者未對request的檔案路徑進行檢查,而產生路徑跳脫,使得使用者跳脫至不應存取之檔案目錄
而預防的方法則應將file路徑進行檢驗將跳脫字元過濾掉
而OWASP所提供的ESAPI中的RandomAccessReferenceMap則提供了一個方向
RandomAccessReferenceMap繼承AccessReferenceMap此interface
此interface將direct的物件reference轉換成indirect的reference,避免資訊的洩漏,如db key或filename等欲保護之敏感資料

而RandomAccessReferenceMap則將direct object referencence隨機產生長度6碼(英數字)的indirect references,某種程度上也能有效的降低CSRF的威脅,底下附上一簡單的範例
ps.如果將對應關係儲存起來應該是就目前熱門提供的短網址服務了


/*
*
*/

package mypackage;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.owasp.esapi.errors.AccessControlException;
import java.io.*;
import java.util.HashMap;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.owasp.esapi.reference.*;;

/**
*
*/

public final class RandomAccessReferenceMapExample extends HttpServlet {

private static final long serialVersionUID = 1L;
private static final int MAX_FILE_SIZE = 1024;
private static String DIR = "/home/student/downloads/";
private static final Logger logger = Logger.getLogger("RandomAccessReferenceMapExample.java");

private static RandomAccessReferenceMap accessMap = new RandomAccessReferenceMap();

public void init() throws ServletException {
// 定義可以被存取的資料

String s = (String)accessMap.addDirectReference(DIR + "檔案名稱");
//將檔案完整路徑加入RandomAccessMap並取得對應的indirect reference
logger.info("indirectRef: " + s);
}

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {

String fName = request.getParameter("fName");//由request取得的file參數
String indirectFileRef = (String)accessMap.getIndirectReference(DIR + fName);
//將使用者之輸入加上路徑至map取得其indirect reference,若非事先定義者將取得null
logger.info("indirectRef: " + indirectFileRef);

try {
String directRef = (String)accessMap.getDirectReference(indirectFileRef);
//這裡嘗試將indirect reference送進map取得原本file之direct reference
logger.info("direct: " + directRef);
} catch (AccessControlException e) {
//若無產生AccessControlException則可正常取得檔案
response.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}

byte data[] = new byte[MAX_FILE_SIZE];
int numBytes = 0;
int totalBytesRead = 0;
FileInputStream fis = null;
OutputStream out = null;

try {
fis = new FileInputStream (DIR + request.getParameter("fName"));
while (numBytes != -1 && totalBytesRead < MAX_FILE_SIZE) {
numBytes = fis.read(data, totalBytesRead, MAX_FILE_SIZE - totalBytesRead);
totalBytesRead += numBytes;
}

response.setContentType("text/html");
out = response.getOutputStream();
out.write(data, 0, totalBytesRead);
} catch(IOException e) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} finally {
fis.close();
out.close();
}
}
}

沒有留言: