Androidアプリケーションにユーザー設定を保存する最も適切な方法は何ですか


308

ユーザー名/パスワードを使用してサーバーに接続するアプリケーションを作成しています。「パスワードを保存」オプションを有効にして、ユーザーがアプリケーションを起動するたびにパスワードを入力する必要がないようにします。

私は共有設定でそれをやろうとしていましたが、これが最善の解決策かどうかはわかりません。

Androidアプリケーションでユーザーの値/設定を保存する方法についての提案をいただければ幸いです。

回答:


233

一般に、SharedPreferencesは設定を保存するための最善の方法です。そのため、一般的には、アプリケーションとユーザー設定を保存するためのそのアプローチをお勧めします。

ここでの唯一の関心領域は、あなたが節約しているものです。パスワードは常に保存するのが難しいので、クリアテキストとして保存する場合は特に注意が必要です。Androidアーキテクチャは、他のアプリケーションが値にアクセスできないようにアプリケーションのSharedPreferencesがサンドボックス化されているため、セキュリティが確保されていますが、電話に物理的にアクセスすると、値にアクセスできる可能性があります。

可能であれば、アクセスを提供するためにネゴシエートされたトークンを使用するようにサーバーを変更することを検討します(OAuthなど)。あるいは、ある種の暗号ストアを構築する必要があるかもしれませんが、それは簡単ではありません。少なくとも、ディスクに書き込む前にパスワードを暗号化していることを確認してください。


3
サンドボックスとはどういう意味ですか?
Abhijit

14
サンドボックスプログラムとは、プロセスや情報(共有設定など)が他のアプリケーションから隠されたままのアプリケーションです。パッケージで実行されているAndroidアプリケーションは、別のパッケージ内の何にも直接アクセスできません。これが、同じパッケージ内のアプリケーション(常にあなたのもの)が他のアプリケーションからの情報にアクセスできる理由です
Korcholis

@Reto Meier私の要件は、トークンを使用しているために公開されているWebサービスを保護することです。共有設定に保存することは安全ですか?私のアプリケーションには起動ブロードキャストレシーバーがあり、ルート化されたデバイスが見つかった場合、すべてのsharedpreferencesデータを削除します。これで私のトークンを保護できますか?
pyus13 2013年

1
パーandroid-developers.blogspot.com/2013/02/...ユーザーの資格情報がMODE_PRIVATEフラグを設定して保存する必要があり、内部ストレージに保存されている(攻撃に対して最終的に開いているローカルパスワードの任意の並べ替えを保存に関する同じ警告で)。つまり、MODE_PRIVATEローカルに保存されたデータを難読化する有効性の観点から、SharedPreferences での使用は、内部ストレージで作成されたファイルで同じことを行うことと同等ですか?
qix

6
共有設定にパスワードを保存しないでください。ユーザーが携帯電話を紛失した場合、パスワードを失っています。読み込まれます。そのパスワードを他の場所で使用した場合、使用したすべての場所が侵害されます。さらに、パスワードを使用するとパスワードが変更される可能性があるため、このアカウントは完全に失われました。これを行う正しい方法は、一度サーバーにパスワードを送信し、ログイントークンを受け取ることです。それを共有設定に保存し、リクエストごとに送信します。そのトークンが危険にさらされた場合、他に何も失われません。
Gabe Sechan 2014

211

RetoとfiXeddに同意します。客観的に言えば、SharedPreferencesのパスワードの暗号化に多大な時間と労力を費やすことはあまり意味がありません。設定ファイルにアクセスできる攻撃者は、アプリケーションのバイナリにもアクセスできる可能性が高いため、パスワード。

ただし、そうは言っても、SharedPreferencesにパスワードを平文で保存するモバイルアプリケーションを特定し、それらのアプリケーションに不利な光を当てる宣伝活動が行われているようです。いくつかの例については、http://blogs.wsj.com/digits/2011/06/08/some-top-apps-put-data-at-risk/およびhttp://viaforensics.com/appwatchdogを参照してください。

セキュリティ全般にもっと注意を払う必要がありますが、この1つの特定の問題に対するこの種の注意は、実際には全体的なセキュリティを大幅に向上させるものではないと主張します。ただし、認識はそのままであるため、SharedPreferencesに配置するデータを暗号化するソリューションを次に示します。

これに独自のSharedPreferencesオブジェクトをラップするだけで、読み取り/書き込みデータはすべて自動的に暗号化および復号化されます。例えば。

final SharedPreferences prefs = new ObscuredSharedPreferences( 
    this, this.getSharedPreferences(MY_PREFS_FILE_NAME, Context.MODE_PRIVATE) );

// eg.    
prefs.edit().putString("foo","bar").commit();
prefs.getString("foo", null);

これがクラスのコードです:

/**
 * Warning, this gives a false sense of security.  If an attacker has enough access to
 * acquire your password store, then he almost certainly has enough access to acquire your
 * source binary and figure out your encryption key.  However, it will prevent casual
 * investigators from acquiring passwords, and thereby may prevent undesired negative
 * publicity.
 */
public class ObscuredSharedPreferences implements SharedPreferences {
    protected static final String UTF8 = "utf-8";
    private static final char[] SEKRIT = ... ; // INSERT A RANDOM PASSWORD HERE.
                                               // Don't use anything you wouldn't want to
                                               // get out there if someone decompiled
                                               // your app.


    protected SharedPreferences delegate;
    protected Context context;

    public ObscuredSharedPreferences(Context context, SharedPreferences delegate) {
        this.delegate = delegate;
        this.context = context;
    }

    public class Editor implements SharedPreferences.Editor {
        protected SharedPreferences.Editor delegate;

        public Editor() {
            this.delegate = ObscuredSharedPreferences.this.delegate.edit();                    
        }

        @Override
        public Editor putBoolean(String key, boolean value) {
            delegate.putString(key, encrypt(Boolean.toString(value)));
            return this;
        }

        @Override
        public Editor putFloat(String key, float value) {
            delegate.putString(key, encrypt(Float.toString(value)));
            return this;
        }

        @Override
        public Editor putInt(String key, int value) {
            delegate.putString(key, encrypt(Integer.toString(value)));
            return this;
        }

        @Override
        public Editor putLong(String key, long value) {
            delegate.putString(key, encrypt(Long.toString(value)));
            return this;
        }

        @Override
        public Editor putString(String key, String value) {
            delegate.putString(key, encrypt(value));
            return this;
        }

        @Override
        public void apply() {
            delegate.apply();
        }

        @Override
        public Editor clear() {
            delegate.clear();
            return this;
        }

        @Override
        public boolean commit() {
            return delegate.commit();
        }

        @Override
        public Editor remove(String s) {
            delegate.remove(s);
            return this;
        }
    }

    public Editor edit() {
        return new Editor();
    }


    @Override
    public Map<String, ?> getAll() {
        throw new UnsupportedOperationException(); // left as an exercise to the reader
    }

    @Override
    public boolean getBoolean(String key, boolean defValue) {
        final String v = delegate.getString(key, null);
        return v!=null ? Boolean.parseBoolean(decrypt(v)) : defValue;
    }

    @Override
    public float getFloat(String key, float defValue) {
        final String v = delegate.getString(key, null);
        return v!=null ? Float.parseFloat(decrypt(v)) : defValue;
    }

    @Override
    public int getInt(String key, int defValue) {
        final String v = delegate.getString(key, null);
        return v!=null ? Integer.parseInt(decrypt(v)) : defValue;
    }

    @Override
    public long getLong(String key, long defValue) {
        final String v = delegate.getString(key, null);
        return v!=null ? Long.parseLong(decrypt(v)) : defValue;
    }

    @Override
    public String getString(String key, String defValue) {
        final String v = delegate.getString(key, null);
        return v != null ? decrypt(v) : defValue;
    }

    @Override
    public boolean contains(String s) {
        return delegate.contains(s);
    }

    @Override
    public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener onSharedPreferenceChangeListener) {
        delegate.registerOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener);
    }

    @Override
    public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener onSharedPreferenceChangeListener) {
        delegate.unregisterOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener);
    }




    protected String encrypt( String value ) {

        try {
            final byte[] bytes = value!=null ? value.getBytes(UTF8) : new byte[0];
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
            SecretKey key = keyFactory.generateSecret(new PBEKeySpec(SEKRIT));
            Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
            pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(Settings.Secure.getString(context.getContentResolver(),Settings.Secure.ANDROID_ID).getBytes(UTF8), 20));
            return new String(Base64.encode(pbeCipher.doFinal(bytes), Base64.NO_WRAP),UTF8);

        } catch( Exception e ) {
            throw new RuntimeException(e);
        }

    }

    protected String decrypt(String value){
        try {
            final byte[] bytes = value!=null ? Base64.decode(value,Base64.DEFAULT) : new byte[0];
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
            SecretKey key = keyFactory.generateSecret(new PBEKeySpec(SEKRIT));
            Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
            pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(Settings.Secure.getString(context.getContentResolver(),Settings.Secure.ANDROID_ID).getBytes(UTF8), 20));
            return new String(pbeCipher.doFinal(bytes),UTF8);

        } catch( Exception e) {
            throw new RuntimeException(e);
        }
    }

}

3
FYI Base64は、APIレベル8(2.2)以降で使用できます。以前のOSでは、iharder.sourceforge.net / current / java / base64などを使用できます。
emmby 2011年

34
はい、書きました。必要に応じて、何の帰属を使用して自由に感じる
emmby

8
仰るとおりです。しかし、パスワードがサーバーでのみ使用されている場合は、公開鍵/秘密鍵の暗号化を使用しないのはなぜですか?パスワードを保存するときのクライアントの公開鍵。クライアントは平文のパスワードを再度読む必要はありませんよね?その後、サーバーはそれを秘密鍵で復号化できます。したがって、誰かがアプリのソースコードを通過しても、サーバーをハッキングして秘密鍵を取得する以外は、パスワードを取得することはできません。
Patrick Boos 2012

4
このコードにいくつかの機能を追加して、それをgithub.com/RightHandedMonkey/WorxForUs_Library/blob/master/src/…の githubに配置しました。暗号化されていない設定から暗号化された設定への移行を処理するようになりました。また、実行時にキーを生成するため、アプリを逆コンパイルしてもキーは解放されません。
RightHandedMonkey 14

3
後日追加されましたが、@ PatrickBoosによるコメントは素晴らしいアイデアです。ただし、この問題の1つは、パスワードを暗号化しても、その暗号を盗んだ攻撃者がサーバーにログインできることです。これは、サーバーが復号化を行うためです。このアプローチの1つの追加は、タイムスタンプと共にパスワードを暗号化することです。これにより、たとえば、最近保存されたパスワードのみを許可するように(「トークン」に有効期限を追加するなど)、特定のユーザーに特定の日付以降のタイムスタンプを要求することもできます(「取り消します」古い「トークン」)。
adevine 2014年

29

Androidアクティビティに単一の設定を保存する最も簡単な方法は、次のようなものです。

Editor e = this.getPreferences(Context.MODE_PRIVATE).edit();
e.putString("password", mPassword);
e.commit();

これらのセキュリティが心配な場合は、パスワードを保存する前にいつでも暗号化できます。


9
この単純なアプローチについては、これ以上あなたに同意することはできません。ただし、保存するパスワードのセキュリティについて常に心配する必要がありますか?アプリケーションによっては、個人情報の盗難の可能性があります。銀行口座や同様に重要なものなどに実際のパスワードを保存しようとする人にこれを指摘するだけです。私はまだあなたに投票します。
While-E

1
パスワードを格納した鍵はどこに格納しますか?他のユーザーが共有設定にアクセスできる場合は、それが鍵となります。
OrhanC1 2014

@ OrhanC1あなたは答えを得ましたか?
eRaisedToX 2017

10

Richardが提供するスニペットを使用すると、保存する前にパスワードを暗号化できます。ただし、設定APIは値を傍受して暗号化する簡単な方法を提供しません。OnPreferenceChangeリスナーを介して保存されるのをブロックでき、理論的には、preferenceChangeListenerを介して変更できますが、結果として無限ループになります。

私は以前、これを達成するために「隠し」設定を追加することを提案していました。それは間違いなく最良の方法ではありません。私はより実行可能であると考える他の2つのオプションを紹介します。

まず、最も簡単なのは、preferenceChangeListenerです。入力した値を取得して暗号化し、別の設定ファイルに保存できます。

  public boolean onPreferenceChange(Preference preference, Object newValue) {
      // get our "secure" shared preferences file.
      SharedPreferences secure = context.getSharedPreferences(
         "SECURE",
         Context.MODE_PRIVATE
      );
      String encryptedText = null;
      // encrypt and set the preference.
      try {
         encryptedText = SimpleCrypto.encrypt(Preferences.SEED,(String)newValue);

         Editor editor = secure.getEditor();
         editor.putString("encryptedPassword",encryptedText);
         editor.commit();
      }
      catch (Exception e) {
         e.printStackTrace();
      }
      // always return false.
      return false; 
   }

第二の方法、と私は今、好みの方法は、Override'ing @、EditTextPreferenceを拡張し、独自のカスタム設定を作成することですsetText()し、getText()そのため、メソッドをsetText()暗号化し、パスワード、およびgetText()リターンはnull。


私はこれがかなり古いことを知っていますが、EditTextPreferenceのカスタムバージョンのコードを投稿していただけませんか?
RenniePet 2013

気にしないで、ここで使用可能なサンプルgroups.google.com/forum/#!topic/android-developers/pMYNEVXMa6Mを見つけました。これで問題なく動作しました。このアプローチを提案してくれてありがとう。
RenniePet 2013

6

はい; 答えが少し混ざっているので久しぶりですが、ここにいくつかの一般的な答えがあります。私はこれを狂ったように研究しました、そして良い答えを作るのは困難でした

  1. ユーザーがデバイスのルート権限を取得していないと想定する場合、MODE_PRIVATEメソッドは一般的に安全であると見なされます。データは、元のプログラムだけがアクセスできるファイルシステムの一部にプレーンテキストで保存されます。これにより、ルート化されたデバイス上の別のアプリでパスワードを簡単に取得できます。次に、ルート化されたデバイスをサポートしますか?

  2. AESは、あなたができる最高の暗号化です。私がこれを投稿してからしばらく経っていない場合、新しい実装を開始する場合は、これを調べることを忘れないでください。これに関する最大の問題は、「暗号化キーをどうするか」です。

それで、今、私たちは「鍵をどうするか」にいます。部分。これは難しい部分です。キーを取得することはそれほど悪くないことが判明しました。キー導出関数を使用してパスワードを取得し、かなり安全なキーにすることができます。「PKFDF2で何回パスするか」などの問題が発生しますが、それは別のトピックです

  1. 理想的には、デバイスからAESキーを保存します。安全に、確実に、そして安全にサーバーからキーを取得するための良い方法を理解する必要があります

  2. ある種のログインシーケンスがあります(リモートアクセスのために行う元のログインシーケンスでさえも)。同じパスワードでキージェネレーターを2回実行できます。これが機能する方法は、新しいソルトと新しい安全な初期化ベクトルを使用してキーを2回導出することです。これらの生成されたパスワードの1つをデバイスに保存し、2番目のパスワードをAESキーとして使用します。

ログインすると、ローカルログインでキーが再取得され、保存されているキーと比較されます。それが完了したら、AESの派生キー#2を使用します。

  1. 「一般的に安全な」アプローチを使用して、AESを使用してデータを暗号化し、鍵をMODE_PRIVATEに格納します。これは最近のAndroidブログ投稿で推奨されています。信じられないほど安全ではありませんが、一部の人にとってはプレーンテキストよりも優れています

これらのバリエーションはたくさんあります。たとえば、完全なログインシーケンスの代わりに、クイックPIN(派生)を実行できます。クイックPINは完全なログインシーケンスほど安全ではないかもしれませんが、プレーンテキストよりも何倍も安全です


5

これは少しネクロマンシーであることはわかっていますが、Android AccountManagerを使用する必要があります。このシナリオ用に作成されています。少し面倒ですが、SIMカードが変更されるとローカル認証情報が無効になるため、誰かが携帯電話をスワイプして新しいSIMをその中に投げ込んでも、認証情報が危険にさらされることはありません。

これにより、ユーザーはデバイス上にあるアカウントの保存された資格情報に、すべて1か所からすばやく簡単にアクセス(および削除)できます。

SampleSyncAdapterは、保存されたアカウント資格情報を利用する例です。


1
AccountManagerを使用することは、上記の他の方法よりも安全ではないことに注意してください!developer.android.com/training/id-auth/...
サンダーVersluys

1
AccountManagerの使用例は、異なるアプリ間でアカウントを共有する必要がある場合や、異なる作成者のアプリである場合です。パスワードを保存し、要求しているアプリにそれを与えることは適切ではありません。ユーザー/パスワードの使用が1つのアプリのみの場合は、AccountManagerを使用しないでください。
ドルメン

1
@dolmen、それはまったく正しくありません。AccountManagerは、AuthenticatorのUIDと一致しないアプリにアカウントパスワードを提供しません。名前、はい。認証トークン、はい。パスワード、いいえ。試行すると、SecurityExceptionがスローされます。そして、ユースケースはそれよりはるかに広いです。 developer.android.com/training/id-auth/identify.html
Jon O

5

Androidでの一般的なパスワードの保護について話すために、帽子をリングに投げ込みます。Androidでは、デバイスバイナリは危険にさらされていると見なす必要があります。これは、ユーザーが直接制御するすべてのエンドアプリケーションで同じです。概念的には、ハッカーは必要なバイナリへのアクセスを使用してバイナリを逆コンパイルし、暗号化されたパスワードなどをルート化することができます。

そのため、セキュリティが主な懸念事項である場合は、2つの提案を破棄します。

1)実際のパスワードは保存しないでください。許可されたアクセストークンを保存し、アクセストークンと電話の署名を使用して、サーバー側でセッションを認証します。これの利点は、トークンの有効期間を制限できること、元のパスワードを危険にさらすことなく、後でトラフィックに関連付けるために使用できる適切な署名を持っていることです(たとえば、侵入の試みをチェックして、トークンはそれを役に立たなくします)。

2)2要素認証を利用します。これはより面倒で煩わしいかもしれませんが、一部のコンプライアンス状況では避けられません。



2

これは、質問のタイトル(私がしたように)に基づいてここに到着した人のための補足的な回答であり、パスワードの保存に関連するセキュリティの問題に対処する必要はありません。

共有設定の使用方法

ユーザー設定は通常SharedPreferences、キーと値のペアを使用してAndroidにローカルに保存されます。Stringキーを使用して、関連する値を保存または検索します。

共有設定に書き込む

String key = "myInt";
int valueToSave = 10;

SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt(key, valueToSave).commit();

apply()代わりにcommit()を使用して、すぐにではなくバックグラウンドで保存します。

共有設定から読み取る

String key = "myInt";
int defaultValue = 0;

SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
int savedValue = sharedPref.getInt(key, defaultValue);

キーが見つからない場合は、デフォルト値が使用されます。

ノート

  • 上記のように複数の場所でローカルキー文字列を使用するのではなく、1つの場所で定数を使用する方が良いでしょう。設定アクティビティの上部で次のようなものを使用できます。

    final static String PREF_MY_INT_KEY = "myInt";
  • 私が使用int私の例では、あなたも使用することができputString()putBoolean()getString()getBoolean()、など

  • ドキュメントを見るをください。
  • SharedPreferencesを取得する方法は複数あります。注意すべき点については、この回答を参照してください。

1

この回答は、マークが提案したアプローチに基づいています。EditTextPreferenceクラスのカスタムバージョンが作成され、ビューに表示されるプレーンテキストと、プリファレンスストレージに保存されているパスワードの暗号化されたバージョンとの間で相互に変換されます。

このスレッドで回答したほとんどの人が指摘したように、これはあまり安全な手法ではありませんが、セキュリティの程度は、使用する暗号化/復号化コードに部分的に依存します。しかし、それはかなりシンプルで便利であり、ほとんどのカジュアルなスヌーピングを阻止します。

カスタムEditTextPreferenceクラスのコードは次のとおりです。

package com.Merlinia.OutBack_Client;

import android.content.Context;
import android.preference.EditTextPreference;
import android.util.AttributeSet;
import android.util.Base64;

import com.Merlinia.MEncryption_Main.MEncryptionUserPassword;


/**
 * This class extends the EditTextPreference view, providing encryption and decryption services for
 * OutBack user passwords. The passwords in the preferences store are first encrypted using the
 * MEncryption classes and then converted to string using Base64 since the preferences store can not
 * store byte arrays.
 *
 * This is largely copied from this article, except for the encryption/decryption parts:
 * https://groups.google.com/forum/#!topic/android-developers/pMYNEVXMa6M
 */
public class EditPasswordPreference  extends EditTextPreference {

    // Constructor - needed despite what compiler says, otherwise app crashes
    public EditPasswordPreference(Context context) {
        super(context);
    }


    // Constructor - needed despite what compiler says, otherwise app crashes
    public EditPasswordPreference(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
    }


    // Constructor - needed despite what compiler says, otherwise app crashes
    public EditPasswordPreference(Context context, AttributeSet attributeSet, int defaultStyle) {
        super(context, attributeSet, defaultStyle);
    }


    /**
     * Override the method that gets a preference from the preferences storage, for display by the
     * EditText view. This gets the base64 password, converts it to a byte array, and then decrypts
     * it so it can be displayed in plain text.
     * @return  OutBack user password in plain text
     */
    @Override
    public String getText() {
        String decryptedPassword;

        try {
            decryptedPassword = MEncryptionUserPassword.aesDecrypt(
                     Base64.decode(getSharedPreferences().getString(getKey(), ""), Base64.DEFAULT));
        } catch (Exception e) {
            e.printStackTrace();
            decryptedPassword = "";
        }

        return decryptedPassword;
    }


    /**
     * Override the method that gets a text string from the EditText view and stores the value in
     * the preferences storage. This encrypts the password into a byte array and then encodes that
     * in base64 format.
     * @param passwordText  OutBack user password in plain text
     */
    @Override
    public void setText(String passwordText) {
        byte[] encryptedPassword;

        try {
            encryptedPassword = MEncryptionUserPassword.aesEncrypt(passwordText);
        } catch (Exception e) {
            e.printStackTrace();
            encryptedPassword = new byte[0];
        }

        getSharedPreferences().edit().putString(getKey(),
                                          Base64.encodeToString(encryptedPassword, Base64.DEFAULT))
                .commit();
    }


    @Override
    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
        if (restoreValue)
            getEditText().setText(getText());
        else
            super.onSetInitialValue(restoreValue, defaultValue);
    }
}

これは、それをどのように使用できるかを示しています。これは、設定の表示を制御する「アイテム」ファイルです。3つの通常のEditTextPreferenceビューと1つのカスタムEditPasswordPreferenceビューが含まれていることに注意してください。

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <EditTextPreference
        android:key="@string/useraccountname_key"
        android:title="@string/useraccountname_title"
        android:summary="@string/useraccountname_summary"
        android:defaultValue="@string/useraccountname_default"
        />

    <com.Merlinia.OutBack_Client.EditPasswordPreference
        android:key="@string/useraccountpassword_key"
        android:title="@string/useraccountpassword_title"
        android:summary="@string/useraccountpassword_summary"
        android:defaultValue="@string/useraccountpassword_default"
        />

    <EditTextPreference
        android:key="@string/outbackserverip_key"
        android:title="@string/outbackserverip_title"
        android:summary="@string/outbackserverip_summary"
        android:defaultValue="@string/outbackserverip_default"
        />

    <EditTextPreference
        android:key="@string/outbackserverport_key"
        android:title="@string/outbackserverport_title"
        android:summary="@string/outbackserverport_summary"
        android:defaultValue="@string/outbackserverport_default"
        />

</PreferenceScreen>

実際の暗号化/復号化については、読者の練習問題として残しておきます。私は現在、この記事http://zenu.wordpress.com/2011/09/21/aes-128bit-cross-platform-java-and-c-encryption-compatibility/に基づいていくつかのコードを使用していますが、値は異なりますキーと初期化ベクトル。


1

まず第一に、ユーザーのデータを電話に保存しないでください。電話のどこかにデータを保存する必要がある場合は、アプリのプライベートデータで暗号化する必要があります。ユーザー資格情報のセキュリティは、アプリケーションの優先事項である必要があります。

機密データは安全に保管するか、まったく保管しないでください。デバイスの紛失やマルウェアの感染が発生した場合、安全に保存されていないデータが侵害される可能性があります。


1

Android KeyStoreを使用して、RSBをECBモードで使用してパスワードを暗号化し、SharedPreferencesに保存します。

パスワードを戻したい場合は、SharedPreferencesから暗号化されたパスワードを読み取り、KeyStoreを使用してそれを復号化します。

この方法を使用して、Androidによって安全に保存および管理される公開鍵/秘密鍵のペアを生成します。

これを行う方法に関するリンクは次のとおりです。AndroidKeyStoreチュートリアル


-2

共有設定は、アプリケーションデータを保存する最も簡単な方法です。しかし、誰でもアプリケーションマネージャを介して共有設定データをクリアできる可能性があります。そのため、アプリケーションにとって完全に安全だとは思いません。


-3

パスワードを保存するには、sqlite、セキュリティピットを使用する必要があります。これがパスワードを保存する最良の例です-passwordsafe。ここにソースと説明のリンクがあり ます-http://code.google.com/p/android-passwordsafe/


3
OPは、1つのユーザー名とパスワードのペアを保存する必要があります。この1つの用途のためにデータベーステーブル全体を作成することを検討するのはばかげているでしょう
HXCaine

@HXCaine私は敬意を払って同意しません-ユーザー/パスワードのsqliteテーブルの少なくとも1つの他の使用を見ることができます。(sqliteを使用することによる)リスクを許容できる場合は、単純なアプリケーションログイン認証に加えて、たとえば、テーブルを使用して複数のftpパスワードを格納できます(アプリがftpを使用している場合-自分で使用する場合もあります)。さらに、この操作のためのsqliteアダプタークラスを作成するのは簡単です。
トニーギル2012

2年前のコメントの素敵な復活!正直なところ、私のコメントは回答から1年後のことです:)少数のFTPパスワードを使用しても、SQLiteテーブルの方が、スペースとコーディングの両方の点で、SharedPreferencesよりもはるかにオーバーヘッドが大きくなります。確かにそれは必要ではありません
HXCaine 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.