iOS “弱账号” 暗转 “强账号”

一、背景

由于某些历史原因,我们产品中50%以上活跃用户是弱账户。即 客户端按照某种规则生成的一个伪id 存在keychain 里,作为这个用户的唯一标识,实现快速登录。正常情况下是不会有问题。

最近,公司的apple 账号需要更换,这样我们的iOS app 需要从老账号 迁移到 新账号上,苹果也提供了迁移功能。那么,问题来了,apple 账号的变换 会导致 teamid 的变换,而keychain里面的存储 key与 teamid 有所关联。

说白了,teamid 变了,你keychain老账号存储的 伪id就读不到了,那不就等于 50%的弱账户丢失了么?

二、解决方案

1. 通过一些活动引导玩家,弱账户绑定成强账号;(用户行为)

2. 更换存储机制,实现 伪id 在不同apple账户(teamid不同情况下)依然保持一样,或是能够映射过去;

a. 因为keychain 与 teamid关联,所以转移周期内,转存储沙箱;缺点用户卸载,后期再安装将丢失弱账户;

b. 粘贴板,考虑到转移过程的长期性 以及 粘贴板自身的特性,并不能很好解决问题;

c. 浏览器缓存,跟粘贴板一样,限制太多;

3. 偷偷的实现弱账号 绑定成 强账号;(用户无感知)

4. 放弃部分玩家;(通过客服找回)

还有其它一些小方案都不是很合适,就不一一列出。最后我们选择了,1、2.a、3、4同步进行,尽可能减少弱账号的丢失。我们重点讲下第三点,其它没有什么好讲的。存储沙箱时候注意加密。

三、“弱账号” 绑定成 “强账号”

想偷偷实现 “弱账号” 绑定成 “强账号”,读取真实的 苹果设备号、手机号 等等,能想到的、以前能做到的都已经被苹果封堵了。如果通过一些非官方api,被发现,那问题更大。

那么只能退而寻求第三方辅助。移动有推出“一键免密登录”的SDK,感觉有点靠谱,不需要用户填写短信验证码、手机号码,可以实现三网的一键免密登录。

它们SDK提供了一个接口:

//显式登录
+ (void)getTokenExpWithController:(UIViewController *)vc
                         complete:(void (^)(id sender))complete;

 可以通过这个接口获取:(拿到openId 和 securityphone 可以实现强绑定)

{
    capaids = "4,7";
    openId = "eVMQwBpV1osTsEq64HBpWWag9WX-HdRA7DwKEOPh5UG2maarLm1g";
    phonescrip = 968B5C447F12383C0767526C123847B60AF29BE543D735D0E4EB841EE3988AE1EF67B5DC21978332BC36876C9FF9C9CD8BA1139465419B4D600FF05144298FE876FF4A6D3D02C5ADA0DB9CA94291981F0DF882D3671052560CBC031CE9103162E1F22EBEE4E539F6A1880EA5201AA27B6CC279E98922DF356BB69032DC135250;
    privateKey = 83AFF2D124CA4133;
    securityphone = "173****3919";
}

  但是必须要弹出移动的授权界面:

好的,有这么一步,用户体验 会很不好,我们得想办法不展示这个界面,依然能拿到我们想要的数据。

四、人肉逆向

1.首先我用了class-dump,看看能不能搞出一些头文件,以失败告终。

然后我就想不弹出他们页面,依然能拿到数据,那必须知道他们界面的名称。

2.因为这个界面是模态出来的,所以method swizzling了模态方法:

- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^ __nullable)(void))completion NS_AVAILABLE_IOS(5_0);

 从而知道他们的导航类是 UANavigationController;

3.写了个定时器延迟10s获取最顶层页面,并且打印了VC栈:

UABufferViewController,UAOneKeyViewController(这里有打印这2个类的所有属性 以及 方法)

通过UAOneKeyViewController的指针,意外的发现了我需要的参数在一个字典里面phoneNumAccount

,这个字典里面存储了

{
    capaids = "4,7";
    openId = "eVMQwBpV1osTsEq64HBpWWag9WX-HdRA7DwKEOPh5UG2maarLm1g";
    phonescrip = 968B5C447F12383C0767526C123847B60AF29BE543D735D0E4EB841EE3988AE1EF67B5DC21978332BC36876C9FF9C9CD8BA1139465419B4D600FF05144298FE876FF4A6D3D02C5ADA0DB9CA94291981F0DF882D3671052560CBC031CE9103162E1F22EBEE4E539F6A1880EA5201AA27B6CC279E98922DF356BB69032DC135250;
    privateKey = 83AFF2D124CA4133;
    securityphone = "173****3919";
}

  这样离我想要的东西又进了一步。

4.紧接着,我method swizzling了phoneNumAccount的set方法,并且在-(void)qiye_setPhoneNumAccount:(NSDictionary*)dic;  这个方法里面打了断点,这样我就能看到写值phoneNumAccount的详细堆栈;

我画红线的2个步骤非常关键,一个是跳过移动api的方法,另外一个可以拿到所有通信的内容。

是的我不需要调用移动+ (void)getTokenExpWithController:(UIViewController *)vc complete:(void (^)(id sender))complete; 这个方法,直接绕过他们强制出现的用户同意界面。

然后我只要调用:

    UIViewController * vc = [[NSClassFromString(@"UABufferViewController") alloc] init];
    [vc performSelector: NSSelectorFromString(@"loginExplicitly")];

  就可以通过-(void)qiye_setPhoneNumAccount:(NSDictionary*)dic;拿到openId 和 securityphone ;

5. 还有一个,UANetwork这个类暴露出来了,我们通过method swizzling:

+(void)qiye_requestNetworkWithURL:(id) url params:(id)params method:(id)method completion:(void (^)(id))completion
{
    NSLog(@"qiye_requestNetworkWithURL........%@  %@   %@",url,params,method);
    void (^netBlock)(id) = ^(id value){
        NSLog(@"Block:%@",value);
       if(completion) completion(value);
    };
    [self qiye_requestNetworkWithURL:url params:params method:method completion:netBlock];
}

 然后他们的网络请求参数,以及返回 什么的 ,都拿到了。

https://www.cmpassport.com/unisdk/rs/ckRequest
 Block:{
    capaids = "4,7";
    desc = success;
    eappid = "6h/kM9lZGkjoGumpei8nYQ==";
    epackage = "Y6PKTCDWcDJJnDxs6pwKBkqR5fo14Zygd8lupt+9fLc=";
    esign = "<null>";
    privateKey = 83AFF2D124CA4133;
    resultCode = 103000;
    servertime = 17;
    sourceid = 800120180112107085;
}

https://wap.cmpassport.com:8443/log/logReport
Block:{
    config =     {
        crashlog = 1;
        limitM = 50;
        limitN = 3;
        limitX = 100;
        norlog = 1;
        sizelimit = 1;
        timelimit = 1;
    };
    desc = success;
    resultCode = 103000;
}

http://www.cmpassport.com/unisdk/rs/getTelecomPhoneNumberNotify?ver=1.0&result=0&state=%7B%22timeStamp%22%3A%2220180115184428437%22%2C%22clientType%22%3A%221%22%2C%22appId%22%3A%228013416909%22%2C%22format%22%3A%22json%22%2C%22params%22%3A%22800120180112107085%22%2C%22version%22%3A%221.1%22%7D&msg=success&mobile=8E482352DBECD75680483DB0B4F8EBC5&sign=F43348BE1ED50B97B2F2BB392C0DE7632C73124E
Block:{
    resultCode = 103000;
    resultdata =     {
        openId = "eVMQwBpV1osTsEq64HBpWWag9WX-HdRA7DwKEOPh5UG2maarLm1g";
        phonescrip = 968B5C447F12383C0767526C123847B60AF29BE543D735D0E4EB841EE3988AE1EF67B5DC21978332BC36876C9FF9C9CD8BA1139465419B4D600FF05144298FE876FF4A6D3D02C5ADA0DB9CA94291981F0DF882D3671052560CBC031CE9103162E1F22EBEE4E539F6A1880EA5201AA27B6CC279E98922DF356BB69032DC135250;
        securityphone = "173****3919";
    };
}

  

然后,我们就可以偷偷的实现强绑定了,但是前提是用户有使用了sim卡,并且开着4G网络。

总结:我是不是过分了,不推荐大家这样做。

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #4dbf56; background-color: #282b35 }
p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #ffffff; background-color: #282b35 }
span.s1 { color: #c2349b }
span.s2 { color: #00afca }

原文地址:https://www.cnblogs.com/qiyer/p/8296911.html

时间: 2024-08-30 03:20:58

iOS “弱账号” 暗转 “强账号”的相关文章

iOS开发项目篇—20存储账号信息

iOS开发项目篇—20存储账号信息 一.简单说明 1.不论请求是否成功,都在发送Post请求后,隐藏遮罩. 2.在授权成功后,切换根控制器. (1)说明 切换到控制器有几种情况,要么是切换到新特性,要么是切换到“首页”. 没有必要每次进入程序都需要登录,且每次返回的数据都是一样的,所以只需要把拿到的信息保存到沙盒里就可以了. 判断上次有没有登录成功(把拿到的access_token保存到沙盒中,如果沙盒中有access_token,说明上次登录成功),如果上次登陆成功,那么就判断是否要进入新特性

IOS 如何成为开发者&amp;购买开发者账号 感想

1.申请apple id  要注意 选择你在的国家 比如 China就会在右下角的页面出校圆圈的中国国旗,不然他们会说“无法接收你的请求”.我苦恼了半天,最后我重新申请apple ID 操作的,因为 我在原来的id 加上国家了 后来也不行 ,因为 enrollment的流程 有不可逆的嫌疑.尤其是到付款时候 你无法修改之前流程的步骤了.所以 我申请了apple ID 浪费了几个. 2. Bill 账单信息 要和信用卡 账单填写一致.不然不行 因为 银行说我没有还款能力不给我办 555555. 于

Xamarin iOS教程之申请付费开发者账号下载证书

Xamarin iOS教程之申请付费开发者账号下载证书 Xamarin iOS使用真机测试应用程序 在讲解iOS Simulator时,已经提到了虽然iOS Simulator可以模仿真实的设备,但是还是有很多的缺陷,如打电话.发送SMS信息.获取位置数据等.如果想要实现iOS Simulator实现不了的功能,就需要使用真机对应用程序进行测试.本节将讲解如何使用真机对应用程序进行测试. Xamarin iOS申请付费开发者账号 使用真机测试,需要申请和下载证书.对于证书的申请和下载必须成为一个

iOS———如何申请苹果公司开发者账号流程详细图文介绍(含邓白氏编码的申请方法详细介绍)

因为公司需要,现将之前申请的个人苹果开发者账号会籍迁移到公司名称下 (意思就是之前我们的app 上传到app stroe上面的时候显示的是个人作品,电视迁移完以后,app下面会显示的是公司名称,然后在公司下面可以添加个人开发者名称) 这也是我第一次申请邓白氏编码,在申请之前也找过网上的方法,但是都写的不够全面,看得人不明白,所以在我申请的整个流程中,我将这些过程记录下来,一遍以后有人需要,整个过程花费时间大概一个多月,当然,所有时间都是花在等待上 下面开始记录: 我们是首先有一个Apple开发者

RHEL账号总结一:账号的分类

账号是一种用来记录单个用户或者多个用户的数据.RHEL中每一个合法的用户都必须拥有账号,才能使用RHEL. 在RHEL上的账号可以分为两类: 用户账号:用来存储单一用户的数据,你也可以使用一个用户账号来存储某一个用户的数据. 组账号:用来存储多个用户的信息,每一个组账号都可以记录一组用户的数据. 在RHEL系统中,每一个种账号可以建立4294967296个:也就是说一台RHEL系统,最多可以建立42亿多个用户账号,以及42亿多个组账号. 我们可以把RHEL的所有账号依照下面两种方法进行分类. 1

android账号与同步之账号管理

在android提供的sdk中,samples目录下有一个叫SampleSyncAdapter的示例,它是一个账号与同步的实例,比如Google原始的android手机可以使用Google账号进行数据的同步.具体 的比如你想实时同步你的通讯录到服务端,这时候你就可以通过这个实例来了解android提供的同步机制,从而实现自己的同步功能. 本片博文先介绍一下账号的管理部分.至于账号管理的代码主要是在authenticator包下的三个类里面,还有就是一个叫authenticator的xml文件.

iOS开发 .framework的Optional(弱引用)和Required(强引用)区别, 有错误 Library not found………………

http://www.cnblogs.com/wanyakun/p/3494323.html 强引用(Required)的framework是一定会被加载到内存的,但是弱引用(Optional)的framework只在需要时才会被载入内存,这对于比较大的framework来说,在最初加载的时候会省很多时间. 简单解释一下,有一些库如Social.framework 和 AdSupport.framework,是在iOS6之后才被引入的,还有一些更新了新特性的只能在iOS6+上可用.当你添加一个f

iOS—如何申请苹果公司开发者账号流程详细图文介绍(包括邓白氏编码的申请方法详细介绍)

写在开头~ 这是我第一次申请苹果的企业开发者账号,走了很多弯路,网上很多帖子写的不明不白,这次从申请到拿到结束大概花了1个月多点的时间,上个月就申请完了,一直在忙公司项目的事情,所以现在才有时间来写这篇博客,希望能帮助到大家 转载注明出处:http://www.cnblogs.com/northwan/p/4781127.html 正文: 我们要申请开发者账号,首先就需要先注册一个苹果的appleid,然后再这个账号的基础上去继续,这个相信大家都知道 这是申请appleid的地址: https:

iOS OC 成员变量是强引用还是弱引用

成员变量,本例中的是实例成员变量,是作用于整个类对象内的.从生命周期来看,它比局部变量要长一些,但它默认是私有的,其他对象是无法访问到的. 比如你一个变量放在@interface 中,你申请一个实体时,变量存活周期跟你实体一样. 因为成员变量的作用域是整个类对象内,所以在ARC环境下OC里面的成员变量应该是 strong属性的. 链接:http://www.zhihu.com/question/23347971/answer/24332408 例子: 头文件: @interface ViewCo