摘要:[iOS] 在iOS裡操作SQLite筆記 –SQLite 的SQL injection 隱碼攻擊 防範方式 (四)
在你的App當中使用SQLite資料庫,大多的情形就是一個App一個使用者,然後裡面包含一個SQLite資料庫。
不會像網站上的資料庫,有許多不同的使用者來連結資料庫。在網站上被對應到的資料庫,SQL injection的課題的重要性可能就不需要多提了。
放在App中的SQLite對於SQL injection這個議題防範到底重不重要?可能就是每個人自己評估了,因為除非故意,
自己去刪掉自己資料庫裡面的東西機率看起來也不大,不過這一篇還是稍微來介紹一下在SQLite資料庫裡面的防範資料庫隱碼攻擊的方法。
至少避免使用者幹掉自己的資料庫,還很XX的來Challenge你程式寫的爛….
在前幾個範例之中,我都是用使用者輸入的資訊來組合出我們要下的SQL指令,在這樣的方法中,就會有遭隱碼攻擊的弱點。
例如:
在之前的範例中,我用底下的方式來合成查詢條件,
NSString *sql2 = [NSString stringWithFormat:@"select * from country where engname = %@",self.mytitle.text];
正常的情況下,我預期他組合出來的資料庫指令要如下:
select * from country where engname = 1
但是在隱碼攻擊的時候,可能使用者輸入的資料會讓我組成下方的語法,進而幫助你手刃你的資料庫。
select * from country where engname = 1;DROP TABLE country;--
不管是對資料庫的增刪改查哪一種指令,只要是利用使用者輸入的字串來組合SQL指令都會有這些風險,
在SQLite裡面提供我們使用參數查詢(parameterized queries)來解決這個問題,在SQLite3,可以使用
parameterized queries來置換SQL statement裡面的 ? 字元。以上面討論的新增資料進資料庫,我們要做底下的修改。
首先假設你要修改資料庫的一筆欄位值,需要準備下方的語法。
NSString* safeSqlString = @"UPDATE record SET name=? where id=?";
接下執行這個SQL語法來建立SQLStatment
sqlite3_stmt* statement;
if(sqlite3_prepare(database, [safeSqlString UTF8String], -1, &statement, NULL) != SQLITE_OK)
{
// Add your error handling code here
}
最後則是用綁定的方式,把真正要寫入資料庫的值或者是你的查詢條件的欄位值,傳給SQL指令執行.
if(sqlite3_bind_text(statement, 1, [record.name UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK)
{
// Add your error handling code here
}
那來看一下這樣的指令在上一個章節的部分,程式碼要怎麼來修改?先來看新增資料的指令
sqlite3_stmt *stmt;
//建立新增指令
char *sql = "INSERT INTO country (engname,chname) VALUES (?,?);";
if (sqlite3_prepare_v2(db, sql, -1, &stmt, nil) == SQLITE_OK) {
//真正建立資料庫的指令
NSString * engname = self.mytitle.text;
NSString * chname = self.mydetail.text;
//綁定真正要寫入資料庫的值
sqlite3_bind_text(stmt, 1, [engname UTF8String], -1, NULL);
sqlite3_bind_text(stmt, 2, [chname UTF8String], -1, NULL);
if (sqlite3_step(stmt) != SQLITE_DONE) // ALWAYS RETURNS Error: NULL
NSLog(@"Error updating table: %s", sqlite3_errmsg(db));
sqlite3_reset(stmt);
}
//清除sqlite3_stmt物件
sqlite3_finalize(stmt);
這樣修改就完成了新增資料的部分。
在查詢子句中我們也要做一些修正,
- (IBAction)querydata:(id)sender{
//建立查詢語法
NSString* safeSqlString =[NSString stringWithFormat:@"select * from country where engname = ?"];
//建立條件參數
NSString* engname = [NSString stringWithFormat:@"%@",self.mytitle.text];
//建立sqlite3_stmt物件
sqlite3_stmt* statement;
if (sqlite3_prepare_v2(db, [safeSqlString UTF8String], -1, &statement,nil) == SQLITE_OK) {
//置換綁定的參數值
if(sqlite3_bind_text(statement, 1, [engname UTF8String], -1, NULL) != SQLITE_OK)
{//Error Handling Code
NSAssert1(0,@"code1%s",sqlite3_errmsg(db));
sqlite3_finalize(statement);
return;
}
sqlite3_reset(statement);
TabelDatas = [self statementtoMSarray:statement];
[self.mytable reloadData];
} else {
NSLog(@"%s",sqlite3_errmsg(db));
}
sqlite3_finalize(statement);
}
參考資料
How to prevent SQL Injection in iOS apps?
http://technet.weblineindia.com/mobile/how-to-prevent-sql-injection-in-ios-apps/2/
iOS Quick Tips: Avoiding SQL injection attacks with parameterized queries in sqlite3