当前位置: 代码网 > it编程>编程语言>C/C++ > Token安全存储的几种方式小结

Token安全存储的几种方式小结

2025年04月18日 C/C++ 我要评论
1. encryptedsharedpreferencesencryptedsharedpreferences是一个开源库,用于对sharedpreferences进行加密存储,提供了更高的安全性。示

1. encryptedsharedpreferences

encryptedsharedpreferences 是一个开源库,用于对 sharedpreferences 进行加密存储,提供了更高的安全性。

示例代码

// 创建 encryptedsharedpreferences
masterkeys.keypair keypair = masterkeys.generatekeypair(context, masterkeys.aes256_gcm_spec);
string keyalias = keypair.getalias();

encryptedsharedpreferences encryptedsharedpreferences = encryptedsharedpreferences.create(
        context,
        "encrypted_prefs",
        keyalias,
        encryptedsharedpreferences.prefkeyencryptionscheme.aes256_siv,
        encryptedsharedpreferences.prefvalueencryptionscheme.aes256_gcm
);

// 存储 token
sharedpreferences.editor editor = encryptedsharedpreferences.edit();
editor.putstring("token", token);
editor.apply();

// 获取 token
string token = encryptedsharedpreferences.getstring("token", null);

2. sqlcipher

sqlcipher 是一个开源库,用于对 sqlite 数据库进行加密存储,适用于需要更高安全性的场景。

示例代码

// 初始化 sqlcipher 数据库
sqlitedatabase db = sqlitedatabase.openorcreatedatabase(
        new file(context.getfilesdir(), "encrypted.db"),
        "password", // 数据库密码
        null
);

// 创建表并存储 token
db.execsql("create table if not exists tokens (token text)");
db.execsql("insert into tokens (token) values (?)", new object[]{token});
db.close();

3.使用 android keystore加密后存储

keystore 提供了硬件级别的加密保护,即使设备被 root,也很难获取存储在 keystore 中的密钥。
非常适合存储 token、密码等敏感信息。

不过使用 keystore 比较复杂,需要生成密钥对、加密和解密数据等操作。而加密和解密操作会带来一定的性能开销。

示例代码

1. 生成密钥对

在应用首次启动时,生成一个密钥对并存储在 keystore 中。

import android.security.keystore.keygenparameterspec;
import android.security.keystore.keyproperties;
import android.util.base64;

import java.io.ioexception;
import java.security.invalidalgorithmparameterexception;
import java.security.invalidkeyexception;
import java.security.keystore;
import java.security.keystoreexception;
import java.security.nosuchalgorithmexception;
import java.security.nosuchproviderexception;
import java.security.unrecoverableentryexception;
import java.security.cert.certificateexception;

import javax.crypto.cipher;
import javax.crypto.keygenerator;
import javax.crypto.secretkey;
import javax.crypto.spec.gcmparameterspec;

public class keystoremanager {
    private static final string keystore_provider = "androidkeystore";
    private static final string key_alias = "myappkeyalias";
    private static final string encryption_algorithm = keyproperties.key_algorithm_aes;
    private static final string encryption_block_mode = keyproperties.block_mode_gcm;
    private static final string encryption_padding = keyproperties.encryption_padding_none;
    private static final string encryption_transformation = encryption_algorithm + "/"
            + encryption_block_mode + "/" + encryption_padding;

    private keystore keystore;

    public keystoremanager() throws keystoreexception, certificateexception, nosuchalgorithmexception, ioexception {
        keystore = keystore.getinstance(keystore_provider);
        keystore.load(null);
    }

    public void generatekey() throws nosuchalgorithmexception, invalidalgorithmparameterexception {
        keygenerator keygenerator = keygenerator.getinstance(keyproperties.key_algorithm_aes, keystore_provider);
        keygenerator.init(new keygenparameterspec.builder(key_alias,
                keyproperties.purpose_encrypt | keyproperties.purpose_decrypt)
                .setblockmodes(encryption_block_mode)
                .setencryptionpaddings(keyproperties.encryption_padding_none)
                .build());
        keygenerator.generatekey();
    }

    public byte[] encryptdata(string data) throws exception {
        cipher cipher = cipher.getinstance(encryption_transformation);
        cipher.init(cipher.encrypt_mode, getsecretkey());
        return cipher.dofinal(data.getbytes());
    }

    public string decryptdata(byte[] encrypteddata) throws exception {
        cipher cipher = cipher.getinstance(encryption_transformation);
        cipher.init(cipher.decrypt_mode, getsecretkey());
        return new string(cipher.dofinal(encrypteddata));
    }

    private secretkey getsecretkey() throws unrecoverableentryexception, keystoreexception {
        return (secretkey) keystore.getkey(key_alias, null);
    }
}

2. 使用 keystoremanager

在你的应用中,使用 keystoremanager 来存储和读取 token。

import android.os.bundle;
import android.util.log;

import androidx.appcompat.app.appcompatactivity;

import java.io.ioexception;
import java.security.keystoreexception;
import java.security.nosuchalgorithmexception;
import java.security.unrecoverableentryexception;
import java.security.cert.certificateexception;

public class mainactivity extends appcompatactivity {
    private static final string tag = "mainactivity";

    @override
    protected void oncreate(bundle savedinstancestate) {
        super.oncreate(savedinstancestate);
        setcontentview(r.layout.activity_main);

        try {
            keystoremanager keystoremanager = new keystoremanager();
            // 生成密钥对(只需在首次启动时调用一次)
            keystoremanager.generatekey();

            // 加密 token
            string accesstoken = "your_access_token_here";
            byte[] encryptedaccesstoken = keystoremanager.encryptdata(accesstoken);
            
			//存储请参考下述的几种方式
			
            // 解密 token
            string decryptedaccesstoken = keystoremanager.decryptdata(encryptedaccesstoken);

            log.d(tag, "encrypted token: " + base64.encodetostring(encryptedaccesstoken, base64.default));
            log.d(tag, "decrypted token: " + decryptedaccesstoken);
        } catch (keystoreexception | certificateexception | nosuchalgorithmexception | ioexception | unrecoverableentryexception | invalidalgorithmparameterexception e) {
            e.printstacktrace();
        }
    }
}

代码说明

  1. 生成密钥对

    • 使用 keygenparameterspec 定义密钥的属性。
    • 使用 keygenerator 生成密钥对并存储在 keystore 中。
  2. 加密数据

    • 使用 cipher 对数据进行加密。
    • 返回加密后的字节数组。
  3. 解密数据

    • 使用 cipher 对加密数据进行解密。
    • 返回解密后的字符串。
  4. 存储和读取 token

    • 将加密后的 token 存储在应用的私有目录中(例如 sharedpreferences 或文件系统)。
    • 需要时,读取加密数据并解密。

安全性建议

  1. 密钥管理:确保密钥的生成和使用过程安全,避免密钥泄露。
  2. 存储加密数据:将加密后的 token 存储在应用的私有目录中,避免被其他应用访问。
  3. 错误处理:在实际应用中,需要对各种异常情况进行处理,确保应用的稳定性和安全性。

加密后的几种存储方式

1. 加密后采用 sharedpreferences存储

sharedpreferences 是 android 中一种轻量级的存储方式,适合存储少量的键值对数据。你可以将加密后的 token 存储到 sharedpreferences 中。

// 存储加密后的 token 到 sharedpreferences
sharedpreferences sharedpreferences = getsharedpreferences("myapppreferences", mode_private);
sharedpreferences.editor editor = sharedpreferences.edit();
editor.putstring("encryptedtoken", base64.encodetostring(encryptedaccesstoken, base64.default));
editor.apply();

从 sharedpreferences 中读取时:

sharedpreferences sharedpreferences = getsharedpreferences("myapppreferences", mode_private);
string encryptedtoken = sharedpreferences.getstring("encryptedtoken", null);
if (encryptedtoken != null) {
    byte[] encryptedaccesstoken = base64.decode(encryptedtoken, base64.default);
    // 然后可以对 encryptedaccesstoken 进行解密等操作
}

2. 加密后采用sqlite数据库存储

如果应用中有数据库(如 sqlite),也可以将加密后的 token 存储到数据库中。这种方式适合需要结构化存储的场景。

1. tokendatabasehelper 类

以下是 tokendatabasehelper 类的完整代码,用于创建和管理 sqlite 数据库:

import android.content.contentvalues;
import android.content.context;
import android.database.cursor;
import android.database.sqlite.sqlitedatabase;
import android.database.sqlite.sqliteopenhelper;

public class tokendatabasehelper extends sqliteopenhelper {
    private static final string database_name = "token.db";
    private static final int database_version = 1;
    private static final string table_tokens = "tokens";
    private static final string column_id = "id";
    private static final string column_token = "token";

    public tokendatabasehelper(context context) {
        super(context, database_name, null, database_version);
    }

    @override
    public void oncreate(sqlitedatabase db) {
        string createtable = "create table " + table_tokens + "("
                + column_id + " integer primary key autoincrement,"
                + column_token + " text" + ")";
        db.execsql(createtable);
    }

    @override
    public void onupgrade(sqlitedatabase db, int oldversion, int newversion) {
        db.execsql("drop table if exists " + table_tokens);
        oncreate(db);
    }

    public void savetoken(string token) {
        sqlitedatabase db = this.getwritabledatabase();
        contentvalues values = new contentvalues();
        values.put(column_token, token);
        db.insert(table_tokens, null, values);
        db.close();
    }

    public string gettoken() {
        string token = null;
        sqlitedatabase db = this.getreadabledatabase();
        cursor cursor = db.query(table_tokens, new string[]{column_token}, null, null, null, null, null);
        if (cursor != null && cursor.movetofirst()) {
            token = cursor.getstring(cursor.getcolumnindex(column_token));
        }
        cursor.close();
        db.close();
        return token;
    }
}

2. mainactivity 中的实现

在 mainactivity 中,我们将使用 tokendatabasehelper 来存储和读取加密后的 token。

以下是完整的代码:

import android.os.bundle;
import android.util.base64;
import android.util.log;

import androidx.appcompat.app.appcompatactivity;

import java.io.ioexception;
import java.security.keystoreexception;
import java.security.nosuchalgorithmexception;
import java.security.unrecoverableentryexception;
import java.security.cert.certificateexception;

public class mainactivity extends appcompatactivity {
    private static final string tag = "mainactivity";
    private tokendatabasehelper dbhelper;

    @override
    protected void oncreate(bundle savedinstancestate) {
        super.oncreate(savedinstancestate);
        setcontentview(r.layout.activity_main);

        // 初始化数据库帮助类
        dbhelper = new tokendatabasehelper(this);

        try {
            keystoremanager keystoremanager = new keystoremanager();
            // 生成密钥对(只需在首次启动时调用一次)
            keystoremanager.generatekey();

            // 加密 token
            string accesstoken = "your_access_token_here";
            byte[] encryptedaccesstoken = keystoremanager.encryptdata(accesstoken);

            // 将加密后的 token 存储到数据库
            string encodedtoken = base64.encodetostring(encryptedaccesstoken, base64.default);
            dbhelper.savetoken(encodedtoken);

            // 从数据库中读取 token
            string retrievedtoken = dbhelper.gettoken();
            if (retrievedtoken != null) {
                byte[] retrievedencryptedtoken = base64.decode(retrievedtoken, base64.default);
                // 解密 token
                string decryptedaccesstoken = keystoremanager.decryptdata(retrievedencryptedtoken);
                log.d(tag, "decrypted token: " + decryptedaccesstoken);
            }
        } catch (keystoreexception | certificateexception | nosuchalgorithmexception | ioexception | unrecoverableentryexception | invalidalgorithmparameterexception e) {
            e.printstacktrace();
        }
    }
}

3. 代码说明

  1. 加密和存储 token

    • 使用 keystoremanager 加密 token。
    • 将加密后的 token(base64 编码)存储到 sqlite 数据库中。
  2. 读取和解密 token

    • 从数据库中读取加密后的 token。
    • 解密 token 并打印出来。
  3. tokendatabasehelper

    • 提供了 savetoken 和 gettoken 方法,分别用于存储和读取 token 数据。

4. 注意事项

  • 确保 keystoremanager 类的 generatekeyencryptdata 和 decryptdata 方法实现正确。
  • 数据库的 column_token 字段存储的是 base64 编码后的加密数据,确保在存储和读取时正确处理编码和解码。
  • 如果需要支持多条 token 数据,可以在 gettoken 方法中添加逻辑,例如按时间戳排序或指定特定的 token。

3. 加密后采用内部文件存储

如果 token 数据较大,或者需要更安全的存储方式,可以将其存储到内部存储中。内部存储是私有的,其他应用无法访问。

// 存储到内部存储
file file = new file(getfilesdir(), "encryptedtoken.txt");
fileoutputstream fos = new fileoutputstream(file);
fos.write(encryptedaccesstoken);
fos.close();

从内部存储中读取时:

file file = new file(getfilesdir(), "encryptedtoken.txt");
fileinputstream fis = new fileinputstream(file);
byte[] encryptedaccesstoken = new byte[(int) file.length()];
fis.read(encryptedaccesstoken);
fis.close();

4. 云存储服务

如果需要跨设备同步 token,可以考虑使用云存储服务,如 firebase、dropbox 等。

示例代码(使用 firebase)

// 初始化 firebase 数据库
firebasedatabase database = firebasedatabase.getinstance();
databasereference tokensref = database.getreference("tokens");

// 存储 token
tokensref.child("usertoken").setvalue(token);

// 获取 token
tokensref.child("usertoken").addlistenerforsinglevalueevent(new valueeventlistener() {
    @override
    public void ondatachange(datasnapshot datasnapshot) {
        string token = datasnapshot.getvalue(string.class);
        // 使用 token
    }

    @override
    public void oncancelled(databaseerror databaseerror) {
        // 处理错误
    }
});

总结

  • encryptedsharedpreferences:提供加密的 sharedpreferences,适合存储少量敏感数据。
  • sqlcipher:提供加密的 sqlite 数据库,适合需要更高安全性的场景。
  • sqlite 数据库:适合存储结构化数据,支持复杂查询。建议先加密在存储。
  • 文件存储:适合存储简单的文本数据,确保文件权限为 mode_private。建议先加密在存储。
  • sharedpreferences:适合存储少量数据。建议先加密在存储。
  • 云存储服务:适合跨设备同步数据,但需要依赖第三方服务。

以上就是token安全存储的几种方式小结的详细内容,更多关于token安全存储方式的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com