首发于公众号 前端混合开发,欢迎关注。
作为应用开发者,管理我们应用的安全性至关重要。让我们以银行应用为例:实施加密组件并不是一件容易的事。我们必须:
- 与团队讨论并达成一致,选择一个加密算法,例如RSA或三重DES
- 使用复杂的数学来编写一个算法
- 测试该功能并确保其能抵御密码学攻击
- 最后,确保加密方法也具有高效性
这对小团队来说并不是一件容易的任务,因为它涉及到雇佣安全专业人员,这需要时间和金钱。相反,我们可能更应该使用一个已经为我们做了大部分工作的第三方库。
在这篇文章中,你将学习如何在React Native中使用加密库。我们将使用Expo来在这篇文章中设置我们的应用程序。要设置一个基础的Expo项目:
npx create-expo-app --template bare-minimum
我们开始吧
什么是RSA加密?
RSA 在密码学世界中是家喻户晓的名字;HTTPS和SSH使用RSA加密,因为它是一个强大的算法。它使用两个密钥,一个公钥和一个私钥,来加密和解密消息。
它是如何工作的?
该算法执行这些步骤来生成密钥并执行加密:
- 创建两个大的质数,
p
和q
。数字越大,安全性越好。 - 将
p
和q
相乘。将这个结果命名为n
:n = p*q 。 - 选择一个数字,
e
,其中e
应与n
互质 - 使用此公式计算私钥, d :
- 对于加密,取信息, m ,将其转换为数字,然后像这样加密它:
- 要解密,可以使用这个公式:
既然我们已经学习了RSA加密的基础知识,那么让我们来学习一下初始化向量。
初始化向量
初始化向量(IV)是一个随机数,确保即使秘密密钥相同,密文也总是不同的。这防止了攻击者解码数据。
尽管 IV 不是秘密的,但对于每次加密步骤使用不同的 IV 是至关重要的。如果算法在加密操作中重用了一个 IV,即使攻击者不知道秘密密钥,也可能允许攻击者解密密文。
这里有一个更简单的类比:
- 想象一下,你正在使用一种秘密代码对信息进行编码。你开始加密过程是通过写下一个随机的词:这就是 IV。
- 使用不同的随机词重新加密相同的信息会产生不同的密文。这是因为随机词改变了加密的起始点。
- 然而,如果你使用旧的初始化向量来加密你的信息,我们将得到一个与之前操作类似的密文,这就给攻击者一个机会去检查和解码消息的内容
盐值
盐值是在密码被散列之前添加到密码中的一串随机字符。这有助于保护密码不被破解,即使攻击者拥有一份预先计算好的散列列表,如彩虹表。
当用户创建密码时,网站或应用会生成一个随机的盐值,并在对密码进行哈希处理之前将其添加到密码中。然后,服务器将盐值和哈希密码存储在数据库中。
此外,盐值很重要,因为它们使得破解密码变得更加困难。即使攻击者有一份预先计算的哈希值列表,除非他们也有盐值,否则他们将无法破解密码。这是因为盐值改变了函数的输出,使得相同的哈希密码产生差异。
在本文的下一部分,我们将探索一些最常用的React Native加密库。
Expo SecureStore
由Expo团队引入的 SecureStore 是一个库,它允许开发者在设备存储中加密并存储键值对。
要使用 Expo SecureStore,首先在你的项目中安装:
npx expo install expo-secure-store
以下的代码使用 SecureStore 来加密,保存,并从存储中检索数据:
import React, { useEffect, useState } from "react";
import { Text, View } from "react-native";
import * as SecureStore from "expo-secure-store";
//首先使用密钥将数据存储在加密数据库中:
async function storeData() {
await SecureStore.setItemAsync(
"encryption_message_expo",
"这条消息是使用 Expo Secure store 加密的"
);
}
//现在用给定的密钥检索它:
async function retrieveData() {
const result = await SecureStore.getItemAsync("encryption_message_expo");
if (result) {
return result;
}
alert("值无法保存");
}
export default function ExpoSecureStore() {
const [obtainedData, setObtainedData] = useState("");
const performEncryption = async () => {
await storeData();
const data = await retrieveData();
setObtainedData(data);
};
//当组件首次挂载时,保存并检索值:
useEffect(() => {
performEncryption();
}, []);
//现在显示它:
return (
<View>
<Text style={{ fontSize: 15 }}>
'encryption_message_expo' 的加密值:
</Text>
<Text style={{ fontSize: 20 }}> {obtainedData}</Text>
</View>
);
}
要运行此应用,请运行此终端命令:
npm run start
SecureStore的优点与缺点
以下是一些你可能想在你的项目中使用这项技术的原因:
- 得到Expo的支持,这意味着有一个大团队正在积极地更新和优化这个库
- 清晰易懂的文档
- 定期更新
- 支持常量以确保只在特定情况下解密数据,例如,如果设备已经解锁
然而,存在一些缺点:
- 每个键值对的大小可以达到2MB。因此,你不能在加密存储中保存大文件或数据。
- 不支持自定义钩子
React Native MMKV 存储
React Native MMKV Storage 是另一种帮助本地保存数据的选择。尽管默认情况下保存的数据是未加密的,但这个库使切换到安全存储变得容易。
作为第一步,将 react-native-mmkv-storage
集成到你的Expo项目中,如下所示:
npx expo install react-native-mmkv-storage
npx expo prebuild #generate native code
然后,在你的项目中,创建一个名为 useStorage.js
的空白文件。在这里,编写以下代码:
// file name: useStorage.js. This file will hold our custom Hook
// this hook will encrypt, save and retrieve our data.
import { MMKVLoader, useMMKVStorage } from "react-native-mmkv-storage";
//create a db. The 'withEncryption' function encrypts the database.
const MMKV = new MMKVLoader().withEncryption().initialize();
export const useStorage = (key, defaultValue) => {
//our custom hook will get and store data:
const [value, setValue] = useMMKVStorage(key, MMKV, defaultValue);
return [value, setValue];
};
下面的代码片段展示了我们自定义钩子的使用:
import { View, Text } from "react-native";
import { useStorage } from "./useStorage"; //import the Hook
export default function ReactNativeMMKVStorage() {
//access the database and set a field called 'user'. It's default value will be 'LoRocket'.
const [data, setData] = useStorage("user", "LogRocket");
return (
<View>
<Text>value for user in MMKV {data}</Text>
</View>
);
}
React Native MMKV存储的优点与缺点
以下是一些使其适合于你下一个项目的因素:
- 使用JSI模块,使其性能出众
- 小巧轻便
- 清晰,简洁的文档
- 支持自定义钩子
- 定期更新
然而,我想指出一点:后续的更新引入了重大变化。这意味着你不能在不升级你的项目的 React Native 版本的情况下使用这个库的最新版本。
React Native 密钥链
由知名开发者 Oblador 构建的 React Native Keychain 允许开发者在他们的应用中安全地存储凭据。与本文中提到的其他库不同,Keychain 内置了对 Apple 的 FaceID 的支持。
在你的项目中安装 react-native-keychain
,请运行此终端命令:
npm install react-native-keychain
下面的代码块展示了 React Native Keychain 的基本使用方法:
import { useEffect, useState } from "react";
import { View, Text } from "react-native";
import * as Keychain from "react-native-keychain";
async function saveCredentials() {
const username = "LogRocketName";
const password = "LogPassword";
//save credentials to database
await Keychain.setGenericPassword(username, password);
}
async function getCredentials() {
//now retrieve credentials
const credentials = await Keychain.getGenericPassword();
return credentials;
}
export default function ReactNativeKeychain() {
const [unencryptedData, setUnencryptedData] = useState({});
const performEncryption = async () => {
saveCredentials();
const data = await getCredentials();
setUnencryptedData(data);
};
useEffect(() => {
performEncryption();
}, []);
//finally, display user data:
return (
<View>
<Text>Your username is: {unencryptedData.username}</Text>
<Text>Password is: {unencryptedData.password}</Text>
</View>
);
}
React Native Keychain的优点与缺点
关于它,我喜欢的有几点:
- 频繁更新
- 支持生物识别技术,如面部识别或指纹识别
- 就像Expo的SecureStore一样,它也支持访问控制。这意味着该库在特定情况下也可以解码数据。
- 优秀的文档
然而,存在一个主要的缺陷:钥匙串只针对存储凭证,而不是键值对。
React Native 加密存储(RNES)
RNES 使用平台原生的加密工具来加密和存储敏感数据。
在你的应用中安装 react-native-encrypted-storage
:
npm install react-native-encrypted-storage
这段代码片段展示了库的样例使用:
import EncryptedStorage from "react-native-encrypted-storage";
//为简洁起见,部分代码已移除
const [textData, setTextData] = useState(null);
//首先,将一个项目保存到加密数据库中
async function storeUserSession() {
try {
await EncryptedStorage.setItem("user_name", "LogRocket");
} catch (error) {
console.log("发生错误! ", error);
}
}
//现在尝试检索这个项目:
async function retrieveUserSession() {
try {
const session = await EncryptedStorage.getItem("user_name");
//如果找到项目,则将其存储在状态变量中
if (session !== undefined) {
setTextData(session);
}
} catch (error) {
console.log(error);
}
}
const performEncryption = async () => {
await storeUserSession();
await retrieveUserSession();
};
//在首次装载时,保存并检索 user_name 项目:
useEffect(() => {
performEncryption();
}, []);
return (
<View>
<Text>'user_name' 的加密存储值:{textData}</Text>
<StatusBar style="auto" />
</View>
);
RNES的优点和缺点
以下原因可能使RNES非常适合你的项目:
- 提供了一个用于加密的异步接口
- 一个安全的异步存储替代方案
然而,这个库的一个主要缺点是该项目不经常更新。因此,这可能会在未来引入错误和依赖性冲突。
总结
在这篇文章中,你了解了 RSA 加密、初始化向量(IV)和盐值的基础知识。我们还探讨了一些可信赖的 React Native 安全库。
在我的项目中,我使用了React Native Keychain。这是因为它功能丰富,而且有出色的社区支持。
交流
首发于公众号 大迁世界,欢迎关注。📝 每周一篇实用的前端文章 🛠️ 分享值得关注的开发工具 ❓ 有疑问?我来回答
本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。