开发者社区> apachecn_飞龙> 正文

安卓应用安全指南 4.5.1 使用 SQLite 示例代码

简介: 安卓应用安全指南 4.5.1 使用 SQLite 示例代码 原书:Android Application Secure Design/Secure Coding Guidebook 译者:飞龙 协议:CC BY-NC-SA 4.0 4.5.1.1 创建/操作数据库 在 Android 应用中处理数据库时,可以通过使用SQLiteOpenHelper [10] 来实现数据库文件的适当安排和访问权限设置(拒绝其他应用访问的设置)。
+关注继续查看

安卓应用安全指南 4.5.1 使用 SQLite 示例代码

原书:Android Application Secure Design/Secure Coding Guidebook

译者:飞龙

协议:CC BY-NC-SA 4.0

4.5.1.1 创建/操作数据库

在 Android 应用中处理数据库时,可以通过使用SQLiteOpenHelper [10] 来实现数据库文件的适当安排和访问权限设置(拒绝其他应用访问的设置)。 下面是一个简单的应用示例,它在启动时创建数据库,并通过 UI 执行搜索/添加/更改/删除数据。 示例代码完成了 SQL 注入的防范,来避免来自外部的输入执行不正确的 SQL。

[10] 对于文件存储,可以将绝对文件路径指定为SQLiteOpenHelper构造函数的第二个参数(名称)。 因此,如果指定了 SD 卡路径,则需要注意,存储的文件可以被其他应用读取和写入。

1) SQLiteOpenHelper应该用于创建数据库。

2) 使用占位符。

3) 根据应用要求验证输入值。

SampleDbOpenHelper.java

package org.jssec.android.sqlite;

import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import android.widget.Toast;

public class SampleDbOpenHelper extends SQLiteOpenHelper {

    private SQLiteDatabase mSampleDb; //Database to store the data to be handled

    public static SampleDbOpenHelper newHelper(Context context) {
        //*** POINT 1 *** SQLiteOpenHelper should be used for database creation.
        return new SampleDbOpenHelper(context);
    }

    public SQLiteDatabase getDb() {
        return mSampleDb;
    }

    //Open DB by Writable mode
    public void openDatabaseWithHelper() {
        try {
            if (mSampleDb != null && mSampleDb.isOpen()) {
                if (!mSampleDb.isReadOnly())// Already opened by writable mode
                    return;
                mSampleDb.close();
            }
            mSampleDb = getWritableDatabase(); //It's opened here.
        } catch (SQLException e) {
            //In case fail to construct database, output to log
            Log.e(mContext.getClass().toString(), mContext.getString(R.string.DATABASE_OPEN_ERROR_MESSAGE));
            Toast.makeText(mContext, R.string.DATABASE_OPEN_ERROR_MESSAGE, Toast.LENGTH_LONG).show();
        }
    }

    //Open DB by ReadOnly mode.
    public void openDatabaseReadOnly() {
        try {
            if (mSampleDb != null && mSampleDb.isOpen()) {
                if (mSampleDb.isReadOnly())// Already opened by ReadOnly.
                    return;
                mSampleDb.close();
            }
            SQLiteDatabase.openDatabase(mContext.getDatabasePath(CommonData.DBFILE_NAME).getPath(), null, SQLiteDatabase.OPEN_READONLY);
        } catch (SQLException e) {
            //In case failed to construct database, output to log
            Log.e(mContext.getClass().toString(), mContext.getString(R.string.DATABASE_OPEN_ERROR_MESSAGE));
            Toast.makeText(mContext, R.string.DATABASE_OPEN_ERROR_MESSAGE, Toast.LENGTH_LONG).show();
        }
    }

    //Database Close
    public void closeDatabase() {
        try {
            if (mSampleDb != null && mSampleDb.isOpen()) {
                mSampleDb.close();
            }
        } catch (SQLException e) {
            //In case failed to construct database, output to log
            Log.e(mContext.getClass().toString(), mContext.getString(R.string.DATABASE_CLOSE_ERROR_MESSAGE));
            Toast.makeText(mContext, R.string.DATABASE_CLOSE_ERROR_MESSAGE, Toast.LENGTH_LONG).show();
        }
    }

    //Remember Context
    private Context mContext;
    //Table creation command
    private static final String CREATE_TABLE_COMMANDS
        = "CREATE TABLE " + CommonData.TABLE_NAME + " ("
        + "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
        + "idno INTEGER UNIQUE, "
        + "name VARCHAR(" + CommonData.TEXT_DATA_LENGTH_MAX + ") NOT NULL, "
        + "info VARCHAR(" + CommonData.TEXT_DATA_LENGTH_MAX + ")"
        + ");";

    public SampleDbOpenHelper(Context context) {
        super(context, CommonData.DBFILE_NAME, null, CommonData.DB_VERSION);
        mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        try {
            db.execSQL(CREATE_TABLE_COMMANDS); //Execute DB construction command
        } catch (SQLException e) {
            //In case failed to construct database, output to log
            Log.e(this.getClass().toString(), mContext.getString(R.string.DATABASE_CREATE_ERROR_MESSAGE));
        }
    }

    @Override
    public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
        // It's to be executed when database version up. Write processes like data transition.
    }
}

DataSearchTask.java(SQLite 数据库项目)

package org.jssec.android.sqlite.task;

import org.jssec.android.sqlite.CommonData;
import org.jssec.android.sqlite.DataValidator;
import org.jssec.android.sqlite.MainActivity;
import org.jssec.android.sqlite.R;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import android.util.Log;

//Data search task
public class DataSearchTask extends AsyncTask<String, Void, Cursor> {

    private MainActivity mActivity;
    private SQLiteDatabase mSampleDB;

    public DataSearchTask(SQLiteDatabase db, MainActivity activity) {
        mSampleDB = db;
        mActivity = activity;
    }

    @Override
    protected Cursor doInBackground(String... params) {
        String idno = params[0];
        String name = params[1];
        String info = params[2];
        String cols[] = {"_id", "idno","name","info"};
        Cursor cur;
        //*** POINT 3 *** Validate the input value according the application requirements.
        if (!DataValidator.validateData(idno, name, info)){
            return null;
        }
        //When all parameters are null, execute all search
        if ((idno == null || idno.length() == 0) &&
            (name == null || name.length() == 0) &&
            (info == null || info.length() == 0) ) {
            try {
                cur = mSampleDB.query(CommonData.TABLE_NAME, cols, null, null, null, null, null);
            } catch (SQLException e) {
                Log.e(DataSearchTask.class.toString(), mActivity.getString(R.string.SEARCHING_ERROR_MESSAGE));
                return null;
            }
            return cur;
        }
        //When No is specified, execute searching by No
        if (idno != null && idno.length() > 0) {
            String selectionArgs[] = {idno};
            try {
                //*** POINT 2 *** Use place holder.
                cur = mSampleDB.query(CommonData.TABLE_NAME, cols, "idno = ?", selectionArgs, null, null, null);
            } catch (SQLException e) {
                Log.e(DataSearchTask.class.toString(), mActivity.getString(R.string.SEARCHING_ERROR_MESSAGE));
                return null;
            }
            return cur;
        }
        //When Name is specified, execute perfect match search by Name
        if (name != null && name.length() > 0) {
            String selectionArgs[] = {name};
            try {
                //*** POINT 2 *** Use place holder.
                cur = mSampleDB.query(CommonData.TABLE_NAME, cols, "name = ?", selectionArgs, null, null, null);
            } catch (SQLException e) {
                Log.e(DataSearchTask.class.toString(), mActivity.getString(R.string.SEARCHING_ERROR_MESSAGE));
                return null;
            }
            return cur;
        }
        //Other than above, execute partly match searching with the condition of info.
        String argString = info.replaceAll("@", "@@"); //Escape $ in info which was received as input.
        argString = argString.replaceAll("%", "@%"); //Escape % in info which was received as input.
        argString = argString.replaceAll("_", "@_"); //Escape _ in info which was received as input.
        String selectionArgs[] = {argString};
        try {
            //*** POINT 2 *** Use place holder.
            cur = mSampleDB.query(CommonData.TABLE_NAME, cols, "info LIKE '%' || ? || '%' ESCAPE '@'", selectionArgs, null, null, null);
        } catch (SQLException e) {
            Log.e(DataSearchTask.class.toString(), mActivity.getString(R.string.SEARCHING_ERROR_MESSAGE));
            return null;
        }
        return cur;
    }

    @Override
    protected void onPostExecute(Cursor resultCur) {
        mActivity.updateCursor(resultCur);
    }
}

DataValidator.java

package org.jssec.android.sqlite;

public class DataValidator {

    //Validate the Input value
    //validate numeric characters
    public static boolean validateNo(String idno) {
        //null and blank are OK
        if (idno == null || idno.length() == 0) {
            return true;
        }
        //Validate that it's numeric character.
        try {
                    if (!idno.matches("[1-9][0-9]*")) {
                //Error if it's not numeric value
                return false;
            }
        } catch (NullPointerException e) {
            //Detected an error
            return false;
        }
        return true;
    }

    // Validate the length of a character string
    public static boolean validateLength(String str, int max_length) {
        //null and blank are OK
        if (str == null || str.length() == 0) {
            return true;
        }
        //Validate the length of a character string is less than MAX
        try {
            if (str.length() > max_length) {
                //When it's longer than MAX, error
                return false;
            }
        } catch (NullPointerException e) {
            //Bug
            return false;
        }
        return true;
    }

    // Validate the Input value
    public static boolean validateData(String idno, String name, String info) {
        if (!validateNo(idno)) {
            return false;
        }
        if (!validateLength(name, CommonData.TEXT_DATA_LENGTH_MAX)) {
            return false;
        }else if(!validateLength(info, CommonData.TEXT_DATA_LENGTH_MAX)) {
            return false;
        }
        return true;
    }
}

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
安卓开发小效果--走马灯
使在layout 中 实现文字滚动效果 也就是走马灯的效果 只需要在响应控件里面加上这几行代码就可以                android:singleLine="true"            android:ellipsize="marquee"            androi...
696 0
iOS数据持久化-SQLite数据库使用详解
<h1><strong>使用SQLite数据库</strong></h1> <h2><strong>创建数据库</strong></h2> <p>创建数据库过程需要3个步骤:</p> <p>1、使用sqlite3_open函数打开数据库;</p> <p>2、使用sqlite3_exec函数执行Create Table语句,创建数据库表;</p> <p>3、使用sqlite3_close函数释放
1021 0
使用iOS原生sqlite3框架对sqlite数据库进行操作(二)
使用iOS原生sqlite3框架对sqlite数据库进行操作
100 0
编写高质量的 Java 代码
代码质量概述 代码质量所涉及的5个方面,编码标准、代码重复、代码覆盖率、依赖项分析、复杂度分析。这5方面很大程序上决定了一份代码的质量高低。 我们分别来看一下这5方面:编码标准:这个想必都很清楚,每个公司几乎都有一份编码规范,类命名、包命名、代码风格之类的东西都属于其中。
879 0
【高质量代码】如何写出更高质量的C/C++代码(2):函数设计
函数是组成C/C++程序的基本元素,是将一段执行某项功能的代码进行了封装的代码段。为了实现设计的功能,函数的功能正确性是首要的前提,但是仅仅是正确还不够,其设计的科学性和合理性也是影响函数使用的重要因素。
867 0
【高质量代码】如何写出更高质量的C/C++代码(1):内存管理
内存的管理是C/C++开发程序过程中的一个比较麻烦的问题。对于经验不是足够丰富的程序员来说,开发比较复杂的程序的时候几乎肯定会遇到内存管理方面的bug。
983 0
使用iOS原生sqlite3框架对sqlite数据库进行操作(三)
使用iOS原生sqlite3框架对sqlite数据库进行操作
68 0
使用iOS原生sqlite3框架对sqlite数据库进行操作(一)
使用iOS原生sqlite3框架对sqlite数据库进行操作
97 0
+关注
apachecn_飞龙
Github:@wizardforcel 简书:@ApacheCN_飞龙 微博:@龙雀 CSDN:@wizardforcel ApacheCN 官网:apachecn.org 机器学习交流群:629470233
719
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载