安卓應用安全指南4.5.2使用SQLite規則書
安卓應用安全指南 4.5.2 使用 SQLite 規則書
原書:Android Application Secure Design/Secure Coding Guidebook
譯者:飛龍
使用 SQLite 時,遵循以下規則:
4.5.2.1 正確設定 DB 檔案位置和訪問許可權(必需)
考慮到 DB 檔案資料的保護,DB 檔案位置和訪問許可權設定是需要一起考慮的非常重要的因素。 例如,即使正確設定了檔案訪問權,如果 DB 檔案位於無法設定訪問權的位置,則任何人可以訪問 DB 檔案,例如, SD 卡。 如果它位於應用目錄中,如果訪問許可權設定不正確,它最終將允許意外訪問。 以下是正確分配和訪問許可權設定的一些要點,以及實現它們的方法。 為了保護資料庫檔案(資料),對於位置和訪問許可權設定,需要執行以下兩點。
1) 位置
位於可以由Context#getDatabasePath(String name)
獲取的檔案路徑,或者在某些情況下,可以由Context#getFilesDir11
獲取的目錄。
2) 訪問許可權
設定為MODE_PRIVATE
(只能由建立檔案的應用訪問)模式。
通過執行以下2點,即可
建立其他應用無法訪問的 DB 檔案。 以下是執行它們的一些方法。
- 使用
SQLiteOpenHelper
- 使用
Context#openOrCreateDatabase
建立 DB 檔案時,可以使用SQLiteDatabase#openOrCreateDatabase
。 但是,使用此方法時,可以在某些 Android 智慧手機裝置中建立可從其他應用讀取的 DB 檔案。 所以建議避免這種方法,並使用其他方法。 上述量種方法的每個特徵如下 [11]
[11] 這兩種方法都提供了(包)目錄下的路徑,只能由指定的應用讀取和寫入。
使用SQLiteOpenHelper
當使用SQLiteOpenHelper
時,開發人員不需要擔心很多事情。 建立一個從SQLiteOpenHelper
派生的類,併為構造器的引數指定DB名稱(用於檔名)[12],然後滿足上述安全要求的 DB 檔案會自動建立。
[12] (未在 Android 參考中記錄)由於可以在
SQLiteOpenHelper
實現中,將完整檔案路徑指定為資料庫名稱,因此需要注意無意中指定不能控制訪問許可權的地方(路徑)(例如 SD 卡)。
對於如何使用,請參閱“4.5.1.1 建立/運算元據庫”的具體使用方法。
使用Context#openOrCreateDatabase
使用Context#openOrCreateDatabase
方法建立資料庫時,檔案訪問權應由選項指定,在這種情況下,請明確指定MODE_PRIVATE
。
對於檔案安排,資料庫名稱(用於檔名)可以像SQLiteOpenHelper
一樣指定,檔案將在滿足上述安全要求的檔案路徑中自動建立。 但是,也可以指定完整路徑,因此有必要注意指定 SD 卡時,即使指定MODE_PRIVATE
,其他應用也可以訪問。
MainActivity.java(顯式設定 DB 訪問權的示例)
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Construct database
try {
//Create DB by setting MODE_PRIVATE
db = Context.openOrCreateDatabase("Sample.db", MODE_PRIVATE, null);
} catch (SQLException e) {
//In case failed to construct DB, log output
Log.e(this.getClass().toString(), getString(R.string.DATABASE_OPEN_ERROR_MESSAGE));
return;
}
//Omit other initial process
}
訪問許可權有三種可能的設定:MODE_PRIVATE
,MODE_WORLD_READABLE
和MODE_WORLD_WRITEABLE
。 這些常量可以由或運算子一起指定。 但是,除API_PRIVATE
之外的所有設定,都將在 API 級別 17 和更高版本中被棄用,並且會在 API 級別 24 和更高版本中導致安全異常。 即使對於 API 級別 15 及更早版本的應用,通常最好不要使用這些標誌 [13]。
[13]
MODE_WORLD_READABLE
和MODE_WORLD_WRITEABLE
的更多資訊,以及其使用的注意事項,請參見“4.6.3.2 訪問目錄的許可權設定”。
-
MODE_PRIVATE
只有建立者應用可以讀寫 -
MODE_WORLD_READABLE
建立者應用可以讀寫,其他人只能讀 -
MODE_WORLD_WRITEABLE
建立者應用可以讀寫,其他人只能寫
4.5.2.2 與其它應用共享 DB 資料時,將內容供應器用於訪問控制(必需)
與其他應用共享 DB 資料的方法是,將 DB 檔案建立為WORLD_READABLE
,WORLD_WRITEABLE
,以便其他應用直接訪問。 但是,此方法不能限制訪問或運算元據庫的應用,因此資料可以由非預期的一方(應用)讀或寫。 因此,可以認為資料的機密性或一致性方面可能會出現一些問題,或者可能成為惡意軟體的攻擊目標。
如上所述,在 Android 中與其他應用共享資料庫資料時,強烈建議使用內容供應器。 內容供應器存在一些優點,不僅從安全的角度來實現對 DB 的訪問控制,而且從設計角度來看, DB 綱要結構可以隱藏到內容中。
4.5.2.3 在 DB 操作期間處理變數引數時,必需使用佔位符(必需)
在防止 SQL 注入的意義上,將任意輸入值併入 SQL 語句時,應使用佔位符。 下面有兩個方法用佔位符執行 SQL。
- 使用
SQLiteDatabase#compileStatement()
,獲取SQLiteStatement
,然後使用SQLiteStatement#bindString()
或bindLong()
等,將引數放置到佔位符之後。 - 在
SQLiteDatabese
類上呼叫execSQL()
,insert()
,update()
,delete()
,query()
,rawQuery()
和replace()
時,使用具有佔位符的 SQL 語句。
另外,通過使用SQLiteDatabase#compileStatement()
執行SELECT
命令時,存在“僅獲取第一個元素作為SELECT
命令的結果”的限制,所以用法是有限的。
在任何一種方法中,提供給佔位符的資料內容最好根據應用要求事先檢查。 以下是每種方法的進一步解釋。
使用SQLiteDatabase#compileStatement()
:
資料以下列步驟提供給佔位符:
- 使用
SQLiteDatabase#compileStatement()
獲取包含佔位符的 SQL 語句,如SQLiteStatement
。 - 使用
bindLong()
和bindString()
方法為建立的SQLiteStatement
物件設定佔位符。 - 通過
ExecSQLiteStatement
物件的execute()
方法執行 SQL。
DataInsertTask.java(佔位符的用例):
//Adding data task
public class DataInsertTask extends AsyncTask<String, Void, Void> {
private MainActivity mActivity;
private SQLiteDatabase mSampleDB;
public DataInsertTask(SQLiteDatabase db, MainActivity activity) {
mSampleDB = db;
mActivity = activity;
}
@Override
protected Void doInBackground(String... params) {
String idno = params[0];
String name = params[1];
String info = params[2];
//*** POINT 3 *** Validate the input value according the application requirements.
if (!DataValidator.validateData(idno, name, info)) {
return null;
}
// Adding data task
//*** POINT 2 *** Use place holder
String commandString = "INSERT INTO " + CommonData.TABLE_NAME + " (idno, name, info) VALUES (?, ?, ?)";
SQLiteStatement sqlStmt = mSampleDB.compileStatement(commandString);
sqlStmt.bindString(1, idno);
sqlStmt.bindString(2, name);
sqlStmt.bindString(3, info);
try {
sqlStmt.executeInsert();
} catch (SQLException e) {
Log.e(DataInsertTask.class.toString(), mActivity.getString(R.string.UPDATING_ERROR_MESSAGE));
} finally {
sqlStmt.close();
}
return null;
}
[...]
}
這是一種型別,它預先建立作為物件執行的 SQL 語句,並將引數分配給它。 執行的過程是固定的,所以沒有發生 SQL 注入的可能。 另外,通過重用SQLiteStatement
物件可以提高流程效率。
使用SQLiteDatabase
提供的每個方法:
SQLiteDatabase
提供了兩種型別的資料庫操作方法。 一種是使用 SQL 語句,另一種是不使用 SQL 語句。 使用 SQL 語句的方法是SQLiteDatabase#execSQL()
/rawQuery()
,它以以下步驟執行。
1) 準備包含佔位符的 SQL 語句。
2) 建立要分配給佔位符的資料。
3) 傳遞 SQL 語句和資料作為引數,併為每個過程執行一個方法。
另一方面,SQLiteDatabase#insert()/update()/delete()/query()/replace()
是不使用 SQL 語句的方法。當使用它們時,資料應該按照以下步驟來準備。
1) 如果有資料要插入/更新到資料庫,請註冊到ContentValues
。
2) 傳遞ContentValues
作為引數,併為每個過程執行一個方法(例如,SQLiteDatabase#insert()
)
SQLiteDatabase#insert()
(每個過程的方法的用例):
private SQLiteDatabase mSampleDB;
private void addUserData(String idno, String name, String info) {
//Validity check of the value(Type, range), escape process
if (!validateInsertData(idno, name, info)) {
//If failed to pass the validation, log output
Log.e(this.getClass().toString(), getString(R.string.VALIDATION_ERROR_MESSAGE));
return;
}
//Prepare data to insert
ContentValues insertValues = new ContentValues();
insertValues.put("idno", idno);
insertValues.put("name", name);
insertValues.put("info", info);
//Execute Inser
try {
mSampleDb.insert("SampleTable", null, insertValues);
} catch (SQLException e) {
Log.e(this.getClass().toString(), getString(R.string.DB_INSERT_ERROR_MESSAGE));
return;
}
}
在這個例子中,SQL 命令不是直接寫入,而是使用SQLiteDatabase
提供的插入方法。 SQL 命令沒有直接使用,所以在這種方法中也沒有 SQL 注入的可能。
相關文章
- 安卓應用安全指南4.1.2建立/使用活動規則書安卓
- 安卓應用安全指南5.5.2處理隱私資料規則書安卓
- 安卓應用安全指南翻譯完成安卓
- 安卓應用安全指南4.8輸出到LogCat安卓GC
- 安卓應用安全指南4.7使用可瀏覽的意圖安卓
- 安卓應用安全指南六、困難問題安卓
- 安卓應用安全指南4.1.1建立/使用活動示例程式碼安卓
- 安卓應用安全指南4.3.1建立/使用內容供應器示例程式碼安卓
- 安卓應用安全指南 5.6.1 密碼學 示例程式碼安卓密碼學
- 安卓應用安全指南4.2.3建立/使用廣播接收器高階話題安卓
- 安卓應用安全指南4.6.1處理檔案示例程式碼安卓
- 安卓應用安全指南5.4.1通過HTTPS的通訊示例程式碼安卓HTTP
- 安卓應用優化:使用反射測試安卓裝置是否使用“動態桌布”安卓優化反射
- java安全編碼指南之:執行緒安全規則Java執行緒
- Drools 規則引擎應用
- [譯] 如何在安卓應用中使用 TensorFlow Mobile安卓
- 在安卓上使用OpenCV的指南 - kdnuggets安卓OpenCV
- java安全編碼指南之:Thread API呼叫規則JavathreadAPI
- appium 安卓應用指令碼APP安卓指令碼
- Flutter 如何釋出安卓應用?Flutter安卓
- SQLite 命令列客戶端 sqlite3 使用指南SQLite命令列客戶端
- 50多個惡意安卓應用繞過Google Play,感染了3000萬安卓使用者安卓Go
- 7款最佳安卓日曆應用安卓
- Anbox安卓apk應用安裝及使用說明和常見問題安卓APK
- Go 應用中 package main 的規則GoPackageAI
- 安卓移動應用程式碼安全加固系統設計及實現安卓
- 規則引擎Golang指南 – Mohit KhareGolang
- 徹底理解安卓應用無響應機制安卓
- Sqlite 介紹及應用SQLite
- 安卓 TV 怎麼安裝證書?安卓
- iOS 14.5更新應用追蹤透明度規則,違規應用將下架iOS
- 安卓的切圖規範安卓
- LINUX命令列書寫規則Linux命令列
- Makefile-3-書寫規則
- 安卓版 Google Sheets 表格應用支援滑鼠操作安卓Go
- .NET MAUI 安卓應用開發初體驗UI安卓
- 安卓 VS iOS,誰更安全?安卓iOS
- 安卓7 如何支援Let證書安卓