gnosis@kim:~#

gnosis@kim:~ # cat blog/diva-4-insecure-data-storage-2.md

# [DIVA] 4. Insecure Data Storage - Part 2

[기술 노트]series/DIVA4분 읽기

#Android#App_Security

🎯 Objective

myuser 테이블에 저장된 ID/PW 를 획득하거나, 테이블 구조 자체를 삭제(DROP) 하여 보호장치 없는 DB 저장을 검증하라.


1️⃣ 코드 & 취약점 분석

전체 코드

public class InsecureDataStorage2Activity extends AppCompatActivity {
    private SQLiteDatabase mDB;

    @Override // android.support.v7.app.AppCompatActivity, android.support.v4.app.FragmentActivity, android.support.v4.app.BaseFragmentActivityDonut, android.app.Activity
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        try {
            this.mDB = openOrCreateDatabase("ids2", 0, null);
            this.mDB.execSQL("CREATE TABLE IF NOT EXISTS myuser(user VARCHAR, password VARCHAR);");
        } catch (Exception e) {
            Log.d("Diva", "Error occurred while creating database: " + e.getMessage());
        }
        setContentView(R.layout.activity_insecure_data_storage2);
    }

    public void saveCredentials(View view) {
        EditText usr = (EditText) findViewById(R.id.ids2Usr);
        EditText pwd = (EditText) findViewById(R.id.ids2Pwd);
        try {
            this.mDB.execSQL("INSERT INTO myuser VALUES ('" + usr.getText().toString() + "', '" + pwd.getText().toString() + "');");
            this.mDB.close();
        } catch (Exception e) {
            Log.d("Diva", "Error occurred while inserting into database: " + e.getMessage());
        }
        Toast.makeText(this, "3rd party credentials saved successfully!", 0).show();
    }
}

취약 요소영향
직접 문자열 연결사용자가 ',); DROP …-- 등 SQL 문법 삽입 가능
입력 검증/인코딩 부재SQL Injection → 임의 쿼리 실행, 데이터 변조·삭제
암호화·해시 부재암호, ID 그대로 평문 SQLite DB 내 보관

2️⃣ 실습-공격 시나리오

단계내용결과
① 앱 입력aaa'); DROP TABLE myuser;-- 입력 후 SAVE코드가 그대로 execSQL 에 전달
② SQL InjectionINSERT … 'aaa'); DROP TABLE myuser;--'); → 세미콜론 뒤 DROP 실행테이블 myuser 삭제, 이후 정상 기능 오류
③ 평문 DB 확인adb shell run-as jakhar.aseem.divacd databases && sqlite3 ids2SELECT * FROM myuser; → ID/PW 평문 조회 가능 (삭제 전)

TIP : 루트 권한 없이도 debuggable APK 는 run-as 로 DB 파일에 접근 가능.


3️⃣ Root Cause

  1. Raw SQL 문자열 : 매개변수 바인딩(PreparedStatement) 미사용
  2. 입력 검증 실패 : 정규식·화이트리스트 등 무효
  3. 민감정보 평문 저장 : 해시(scrypt/bcrypt)·암호화 누락
  4. Debuggable + world-readable DB : 파일 권한 강화 안됨

4️⃣ Mitigation & Hardening

영역권장 조치코드 스니펫
SQLi 방어SQLiteStatement 파라미터 바인딩SQLiteStatement st = db.compileStatement("INSERT INTO myuser VALUES (?, ?)"); st.bindString(1, user);
암호 보호비밀번호 → 해시(bcrypt/Argon2)고정키 대신 Android Keystore AES 암호화EncryptedFile, CipherOutputStream
파일권한MODE_PRIVATE + noBackup dir 사용openOrCreateDatabase(name, Context.MODE_PRIVATE, null);
Debuggable OFFandroid:debuggable="false" 릴리스 빌드buildTypes.release { debuggable false }
백업 차단android:allowBackup="false"AndroidManifest.xml

✅ 체크리스트