乐趣区

关于flutter:Flutter-移动安全-ー-Ep2-Strong-Device-Strong-Pin

原文

https://medium.com/kbtg-life/…

前言

在本期节目中,咱们将进一步强化您的挪动应用程序。“然而怎么做呢?”你可能会好奇。让咱们把它比作建造一座房子。为了确保它装备了最高级别的安保零碎,你可能须要在房子四周装置所有的警报器和摄像头。然而如果你碰巧把钥匙留在门口,这些都不重要了!对于安全性,咱们须要思考一个坏黑客可能抉择攻打的每一种可能性,所以这不仅仅是一个解决方案,而后,所有都实现了。咱们必须确保内部和外部的应用程序都是平安的。

上一集,咱们探讨了 SSL。你能够把它设想成房子四周高高的篱笆。尽管爬过来比拟艰难,但还是能够治理的。因而,在本期节目中,咱们将确保没有人意外地把钥匙落在门口。

https://medium.com/kbtg-life/…

在 iOS/Android 中,曾经有一个本地平安 API 来爱护他们的应用程序不受外界的攻打,所以咱们将应用这个 API 来实现 Flutter。让咱们来看看什么是必要的,什么是美妙的。

参考

  • https://pub.dev/packages/flut…
  • https://www.macrumors.com/202…
  • https://pub.dev/packages/flut…
  • https://developer.apple.com/d…
  • https://frida.re/
  • https://developer.android.com…
  • https://medium.com/androiddev…
  • https://github.com/zionspike/…
  • https://www.researchgate.net/…

注释

强制性

平安的数据存储

基本上有两件事你须要记住:

  • 不要在应用程序中保留任何平安信息,比方名字、姓氏、电子邮件、用户名、明码、公民身份,或任何能让黑客追踪并查出用户身份的信息。如果你真的须要保留它,比方一个令牌或者任何你想用来改善用户体验的货色,确保你把它保留在两个操作系统平台都提供的平安的数据存储中。为此,我应用了这个库。

https://pub.dev/packages/flut…

对于 iOS,他们应用 Keychain,即便你删除了应用程序也不会被删除,而对于安卓,他们应用 KeyStore 来存储解密保留的数据的密钥。

  • 额定的平安层总是加密的平安信息,即便 iOS/Android 曾经有了平安存储。这是因为在将来,可能会有一种工具,能够让黑客破解设施上的加密。既然咱们在探讨加密的话题,咱们也须要讨论一下密钥。它应该是动静的和惟一的每个用户,所以咱们决定应用用户本人的明码,因为咱们能够必定,只有应用程序所有者晓得如何解密它与正确的明码和拜访所有保留的数据。

然而,这意味着明码被机密保留在设施上。如果一个黑客暴力破解了一个明码,他们就会晓得这是正确的明码,这可能会更加危险。他们将有足够的工夫解密,因为它是在设施上,所以咱们的解决方案是应用另一层爱护。咱们容许黑客应用任何密钥解密,这样他们就不晓得哪个是正确的密钥来调用咱们的服务器。如果他们输出谬误的明码 3 次,后端会主动锁定他们。这将解决这个问题。这里不提供应用任何密钥进行解密的解决方案。

敞开生产中的日志

开发人员须要一个日志来查看他们的代码是否失常工作。这对于非生产环境来说没有问题,然而对于生产环境来说,您须要敞开它以避免任何人看到它。为此,我通过在 main.dart 中调用以下代码来笼罩 debugPrint 函数

debugPrint = (String message, {int wrapWidth}) {};

这意味着如果咱们应用 debugPrint,它将不会打印任何货色。我把它划分为 main_dev。飞镖和主电极。而后把这个函数放在 main_prod 中。这样咱们就看不到任何生产日志了。至于非刺激性构建,您能够就这样保留它。没有必要增加任何货色。咱们为什么肯定要关掉这根木头?这是因为咱们不想让任何人看到幕后的应用程序。不要给黑客任何他们下一步口头应该是什么的线索。

从当初开始只应用 debugPrint 而不是 print

不反对旧版本操作系统

咱们必须把这个设置老本地,而不是 Flutter。我并不是真的放心 iOS,因为 iOS 用户偏向于依据本文的采用率频繁更新操作系统。

https://www.macrumors.com/202…

在 iOS 14 公布后仅仅 3 个月,81% 的设施都更新了他们的操作系统。请记住,平安就像猫和老鼠,您须要始终远离潜在的威逼。咱们不应该因为操作系统的安全漏洞而尝试反对过期的操作系统版本。在我看来,只反对最新版本或者更早的版本是能够的。例如,当初咱们有 iOS 14,所以咱们应该只反对 iOS 12,13 和 14。这将容许 98% 的用户应用你的应用程序。咱们能够在 Xcode 设定一个最低指标来管制它。

与此同时,Android 是开源的,这意味着谷歌无法控制它。因而,收养率非常低。看看 Android 的布告,看看哪些 Android 操作系统正在变得过期,没有更多的安全补丁。当初他们依然反对 Android 8.0,所以咱们可能不得不将 minSdkVersion 的指标定为 build.gradle 为 26。

简而言之,iOS = 12 及以上 /Android = 26 及以上

只在你须要的时候申请许可

所有开发人员都应该晓得的一件根本事件是,总是在须要时申请权限。不要从一开始就要求许可,只要求你须要的货色。例如,一些应用程序可能会要求拜访您的 GPS 地位,即便没有任何性能须要它。你永远不应该这样做,因为两件事。首先,你在收集不必要的数据,这些数据是用户的私人数据。其次,如果这些数据没有被正确实现,黑客也能够拜访这些数据。因而,为了平安起见,只问你须要什么和什么时候须要它。当用户第一次关上应用程序时,你不心愿用户体验是 10 个弹出窗口。用户将来到,再也不会回来。

越狱检测

对于 Flutter,咱们应用了原生的越狱检测填充,比方用于安卓零碎的 Rootbeer 和用于 iOS 零碎的 DTTJailbreakDetection。这两个都是驰名的。对于 Flutter,我应用这个库。

https://pub.dev/packages/flut…

只管对于有教训的黑客来说,它可能还不够弱小,但至多咱们有货色能够爱护咱们的利用免受没有教训的黑客的攻打。他们在商业 SDK 中有几个解决方案来爱护这一个,然而他们不是强制性的。除非你的利用须要高安全级别,否则 Flutter 越狱检测应该足够了。

利用明码技术进行生物测定

目前,许多应用程序为了更好的用户体验而实现了生物特色辨认认证。然而,他们中的大多数人只是置信 iOS/Android,我并不真的举荐这样做。首先,咱们可能会在 Swift 中看到这样的代码,甚至苹果也举荐这样的代码。

https://developer.apple.com/d…

let reason =“Log in to your account”context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason) { success, error in
   if success {// Login Succeed, do something next} else {// Failed, somebody else!!}
}

每个人都会置信他们的设施。为什么不呢? 嗯,实际上有一个工具叫做 Frida 脚本。

https://frida.re/

浏览之后,你会发现应用这个工具绕过生物计量学工具是如许容易。

这里的教训是 DO n’t just trust boolean from devices。这里有一个来自谷歌的教程,其他人曾经在 Android 版本中实现了它。

https://developer.android.com…

https://medium.com/androiddev…

https://github.com/zionspike/…

这是生物辨认和明码复查的联合。您能够应用同样的概念扑动。也就是说,如果你的应用程序没有任何金融或在线领取性能,你能够跳过这一部分。

不要用纯文本发送明码

有些人可能会说 HTTPS 是足够平安的,为什么咱们必须关怀以纯文本发送明码?事实上,黑客能够应用 MITM (中间人攻打文档) 以纯文本模式轻松检索你的信息。这就是为什么咱们应该在来到挪动应用程序之前对明码进行批改,以防黑客窃听,最好的办法就是用盐来批改明码。

  • hash(password + dynamic salt)

盐应该在短时间内频繁更换,咱们能够做一些根本的事件。

  • hash(password + userID)

只管用户 ID 是惟一的和动静的,但它并不总是变动的。尽管如此,对于根本平安来说,这是能够承受的。然而,如果你想要实现齐全的安全性,你必须找到其余始终在扭转的货色,并且应用迟缓的散列算法,比方 Bcrypt 而不是 SHA256,因为它们须要非凡的硬件来破解。

可选,最好去做

这部分是针对须要额定安全性的金融或银行应用程序。

反调试

对于安卓零碎,咱们将其分为多个性能

  • 敞开 Debuggable 在 buildTypes 局部中增加此标记以 build.gradle。将 release 设置为 false,debug 设置为 true,或者如果须要,能够将两者都设置为 false。
buildTypes {
    release {
        debuggable false
        signingConfig signingConfigs.release
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }

    debug {
        debuggable true
        signingConfig signingConfigs.release
    }

}
  • 阻止调试器
// Open ADB Debugging
if (Settings.Secure.getInt(this.applicationContext.contentResolver, Settings.Global.ADB_ENABLED, 0) == 1) {

}

// Check by using `adb shell getprop ro.crypto.type`
if ((applicationContext.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager).storageEncryptionStatus == DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED) {

}

// flag debuggable in gradle is true
if ((0 != applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE || BuildConfig.DEBUG))  {

}

// Use Debugger in Android Studio to connect for getting log
if (Debug.isDebuggerConnected() || Debug.waitingForDebugger()) {}

您能够复制下面的代码并将其粘贴到 MainActivity.kt。如果是真的,你能够把用户踢出去或者做任何你想做的事件。请容许我解释一下。

  • 关上 ADB 调试避免用户关上 ADB 模式。尽管这没有必要,因为大多数 Android 开发人员总是在须要测试应用程序的时候关上它。这取决于你是否祝酒音讯正告用户或评论它进去。
  • 不反对 ENCRYPTION status unsupported 以查看设施是否反对存储加密。在安卓零碎中,默认状况下它应该是开启的。如果它被敞开了,那么他们的设施就出了问题,因为用户通常不能自己做到这一点。为了避免上述危险,咱们只是不容许任何人应用它。
  • ApplicationInfo.FLAG_DEBUGGABLE 查看咱们在 Gradle 增加的标记调试是否为 true。如果没有,不要让用户应用它。和上一个一样,这是用户无奈扭转的货色,除非有人反向工程你的应用程序,并打包为 APK 再次。
  • 来查看你的应用程序是否连贯到了 Android Studio 调试器。如果是,不要让用户应用它。
  • 至于 iOS,当初还没有简略的办法来实现它,然而你能够找到一些商业 SDK 来帮忙你实现它。

查看设施是否有平安拜访

有些用户可能决定不在他们的设施上装置针、手指扫描或面部扫描。如果有人偷了他们的设施,他们只须要解锁就能够了。领有这种类型的安全措施就像是平安的第一道门。

在 Android 中,我应用 Flutter 通道调用 Flutter 来配置 FlutterEngine 性能,让 Flutter 来决定如何解决这个用户。上面是 Android 的代码,用来查看设施是否有明码。

private val CHANNEL = "com.kbtg.flutter"
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
  if (call.method == "getDeviceHasPasscode") {result.success((getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager).isDeviceSecure)
  } else {result.notImplemented()
  }
}

请拨打以下电话到 Flutter。

try {
    final hasPasscode =
await Storage.platform.invokeMethod('getDeviceHasPasscode');
    if (!hasPasscode) {
        Toast.show(
        "No pin, DANGER DANGER",
        context,
        duration: 5,
        gravity: Toast.BOTTOM,
        );
    }
} on PlatformException catch (e) {debugPrint("==== Failed to scan security'${e.message}'====");
}

如果 hasPasscode 是谬误的,咱们只是烤的音讯,以正告用户,你没有一个针激活在您的设施。

如果须要,敞开第三方键盘

有些第三方键盘可能是歹意的。你永远不会晓得他们是否曾经实现了机密地将你输出的密码发送到他们的服务器上的性能。对于 Android 来说,没有简略的办法来避免这种状况,因为所有的键盘都算作第三方键盘,甚至 Android 本人的键盘。解决这个问题的方法是本人实现一个平安的键盘,办法是应用带有字母和数字的布局从头开始构建一个键盘。

然而,对于 iOS 零碎,咱们能够应用上面的函数来禁用它,只限度应用本地键盘

override func application(_ application: UIApplication, shouldAllowExtensionPointIdentifier extensionPointIdentifier: UIApplicationExtensionPointIdentifier) -> Bool {return extensionPointIdentifier != .keyboard}

查看代码完整性

能够对 IPA 和 APK 进行反编译,以更改外部的一些代码并从新构建以便再次公布。黑客批改的代码可能是你连贯到同一个服务器,然而每个信息也会推送到黑客的服务器。对于 IPA 来说,我并不放心,因为从 App Store 以外装置应用程序是相当简单的。你必须先装置证书并承受某些条件或破解你的设施能力装置它。至于安卓零碎,它很容易伪造一个应用程序,因为它更凋谢,容许任何用户装置内部的 APK 只须要 1-2 次点击。

这就是代码完整性的用武之地。你能够计算你的应用程序的校验和,并在每次关上应用程序之前查看它是否依然和你部署到应用程序商店的应用程序一样。这个概念听起来很简略,然而很难实现。侥幸的是,有一个商业 SDK 能够解决这个问题,所以咱们不须要本人入手。

代码混同

对于咱们实现或保留到应用程序中的所有业务逻辑和平安逻辑,咱们须要确保没有人可能反编译并查看源代码。如果黑客能看到它,他们就会晓得咱们用哪种逻辑来加密数据,或者咱们在哪里存储平安信息。他们能够模拟这种逻辑,发送到他们的服务器,而不是应用咱们的应用程序。对于代码混同,能够应用商业 SDK 来增强应用程序。

你可能曾经留神到我常常提到商业 SDK。有些人可能会想,“如果是这样的话,这篇文章的意义何在?我写这篇文章是为了寻找一种在应用程序中实现它的办法,而不是仅仅转到另一个链接。”

没有人什么都善于。应用商业 SDK 就像领有一个专一于平安工作的业余团队。你本人不能实现和敞开所有的安全漏洞,所以最好把它留给专家,他们晓得他们在做什么,你做你最善于的是开发应用程序。

当初你的利用外壳更加坚硬,你的用户不再把钥匙留在门上,让咱们确保房子的钥匙不容易被复制。我说的是明码和明码

Stronger Pin

Pin 或 password 是一种确认你是账户真正所有者的办法。咱们抉择为应用程序设置一个明码,有两个起因。

更好的用户体验

只管明码更平安,但思考到 A-Z、0-9 和特殊字符能够组成十亿种可能的组合,在设施上应用小键盘输入太难了。在进入你的应用程序之前,你可能会破费大量的工夫。这就是为什么咱们采纳一个 6 位数的引脚来代替。尽管你只能用 4 个数字创立 10,000 个可能的引脚,但 6 个数字给你 1,000,000 个可能性,这是 100 倍的难度。

人们能够在 2-3 秒内输出一个明码,然而一个明码可能会破费他们 10-15 秒,这取决于它有多难。

易于记忆

是的,咱们心愿让黑客难以破解明码,但咱们也心愿咱们的用户可能不费吹灰之力地记住它。因为 pin 是 iOS/Android 的根本平安拜访设施,它不应该公布任何挑战,因为用户曾经习惯了

对于销子,咱们不想让它变得太容易。“‘太容易’到底是什么意思?”你问。好吧,让咱们说得更具体一点。

针没有规范,所以我从网上的钻研中得出了一个想法。请看上面的链接。

https://www.researchgate.net/…

根据上述模式,咱们得出以下规定

  • 不容许有序列号,例如 123456、234567、345678 ー包含反序列号,例如 654321、543210
  • 不要应用「同一行别针」,例如 123123、456456、789789
  • 只容许 3 个或 3 个以上的惟一数字,例如 122112 个是不容许的,但 123321 个是能够的 (即便这可能与下面的统计数据相矛盾)155115,133133,166661 是不容许的,因为只有两个不同的数字在明码中应用
  • 有些人甚至倡议禁用生日别针,比方如果你的生日是 1986 年 6 月 8 日,你就不能用 080686 作为别针来避免黑客利用这些信息入侵。然而,我不这样做只是因为我不在零碎中保留用户的生日

咱们不想制订太多的规定。否则,你会删除所有的明码组合,更蹩脚的是,黑客更容易暴力破解它。咱们能够制订更多的规定,然而如果 100 万种可能性变成 100-200 个引脚,那又有什么意义呢?

应用下面的办法,咱们依然有大概 60,000 种可能性供用户应用。上面是实现它的示例代码。

static bool isPinComplexity(String pin) {
   const notAllowListPin = [
   "123123",
   "456456",
   "789789",
   "012345",
   "123456",
   "234567",
   "345678",
   "456789",
   "567890",
   "098765",
   "987654",
   "876543",
   "765432",
   "654321",
   "543210"
   ];
   final pinSet = new Set.from(pin.split(""));
   final uniqueCharacter = pinSet.length > 2;
   return uniqueCharacter && !notAllowListPin.contains(pin);
}

您能够应用 isPinComplexity 来查看引脚。如果返回 true,咱们容许用户增加它。不要遗记将所有可能的散列也增加到后端。咱们在前端实现只是为了更好的用户体验,这样用户就不用打电话给网络,从服务器和服务器上被回绝,以确保如果黑客试图绕过别针,服务器将不容许它。

你能够依据你的须要在 notAllowListPin 中增加更多的条件,然而我当初很好。

因而,对于咱们施行的所有这些解决方案,咱们要确保咱们的应用程序装备了另一层爱护。


© 猫哥

https://ducafecat.tech/

https://github.com/ducafecat

往期

开源

GetX Quick Start

https://github.com/ducafecat/…

新闻客户端

https://github.com/ducafecat/…

strapi 手册译文

https://getstrapi.cn

微信探讨群 ducafecat

系列汇合

译文

https://ducafecat.tech/catego…

Dart 编程语言根底

https://space.bilibili.com/40…

Flutter 零根底入门

https://space.bilibili.com/40…

Flutter 实战从零开始 新闻客户端

https://space.bilibili.com/40…

Flutter 组件开发

https://space.bilibili.com/40…

Flutter Bloc

https://space.bilibili.com/40…

Flutter Getx4

https://space.bilibili.com/40…

Docker Yapi

https://space.bilibili.com/40…

退出移动版