iOS应用代码注入防护

在应用开发过程中,我们不仅仅需要完成正常的业务逻辑,考虑应用性能、代码健壮相关的问题,我们有时还需要考虑到应用安全的问题。

那么应用安全的问题涉及到很多方面。比如防止静态分析的,代码混淆、逻辑混淆;防止重签名的,应用ID检测、甚至是代码的HASH检测等等。那么这篇文章我想聊聊关于代码的注入检测,因为发现随着iOS系统的更新,我们防护的手段发生了一些变化。

代码注入的方式

代码注入的方式大致分为两种

  • 越狱注入:通过修改 DYLD_INSERT_LIBRARIES 环境变量的值,来插入动态库并执行
  • 非越狱注入:
    • 直接将自定义的Framwork或者dylib库打包进入APP并重签名
    • 利用yololib修改MachO文件,添加库路径.在应用启动时,dyld会加载并执行.

早期防护方式

在工程的Build Settings中找到Other Linker Flages 并添加字段

-Wl,-sectcreate,__RESTRICT,__raestrict,/dev/null

此操作的作用是在可执行文件中添加一个Section.我们使用MachOView分析如下:

当MachO文件中拥有这个字段,那么我们通过越狱环境插入动态库的方式就会失效.起到防护的作用.其原理在DYLD源码中可以分析到.

dyld源码分析

首先这里分析的DYLD源码版本是519.2.2版本. 我们可以通过检索DYLD_INSERT_LIBRARIES定位到_main函数加载插入动态库的代码如下.

  1. if ( sEnv.DYLD_INSERT_LIBRARIES != NULL ) {
  2. for (const char* const* lib = sEnv.DYLD_INSERT_LIBRARIES; *lib != NULL; ++lib)
  3. loadInsertedDylib(*lib);
  4. }
  5. 复制代码

但是早在这个环境变量判断之前,dyld已经做了一个判断

  1. pruneEnvironmentVariables(envp, &apple);
  2. // set again because envp and apple may have changed or moved
  3. setContext(mainExecutableMH, argc, argv, envp, apple);
  4. }
  5. 复制代码

如果判断出进程是restricted!也就是当前进程是限制插入动态库的!就会调用pruneEnvironmentVariables函数移除相关的环境变量.

那么我们的processIsRestricted值什么时候为true呢?

继续分析源码可以发现两个关键函数影响其值.其中 hasRestrictedSegment 函数专门检测RESTRICT段

  1. if ( issetugid() || hasRestrictedSegment(mainExecutableMH) ) {
  2. gLinkContext.processIsRestricted = true;
  3. }
  4. 复制代码

通过注释也能发现.任意进程的__RESTRICT段设置为restricted动态库插入将被限制. 我们进入到processIsRestricted函数内,实现如下.

  1. static bool hasRestrictedSegment(const macho_header* mh)
  2. {
  3. const uint32_t cmd_count = mh->ncmds;
  4. const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header));
  5. const struct load_command* cmd = cmds;
  6. for (uint32_t i = 0; i < cmd_count; ++i) {
  7. switch (cmd->cmd) {
  8. case LC_SEGMENT_COMMAND:
  9. {
  10. const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
  11. //dyld::log(“seg name: %s\n”, seg->segname);
  12. if (strcmp(seg->segname, “__RESTRICT”) == 0) {
  13. const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
  14. const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
  15. for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
  16. if (strcmp(sect->sectname, “__restrict”) == 0)
  17. return true;
  18. }
  19. }
  20. }
  21. break;
  22. }
  23. cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
  24. }
  25. return false;
  26. }
  27. 复制代码

所以通过添加Other Linker Flags 在MachO中设置RESTRICT段赋值为restricted可以用来防护越狱的代码注入. 但是新版的dyld源码中去掉了__RESTRICT检测.从iOS10开始,这种防护手段已失效

DYLD_INSERT_LIBRARIES 检测

那么既然dyld加载过程不再检测__RESTRICT段了我们就手动的检测 DYLD_INSERT_LIBRARIES 环境变量.通过函数可查看当前进程环境变量的值.

  1. char *env = getenv(“DYLD_INSERT_LIBRARIES”);
  2. NSLog(@“%s”,env);
  3. 复制代码

在没有插入动态库时,env为null. 那么一旦为自己的应用写入插件时,我们就可以看到控制台的输出

  1. 2019-01-03 19:20:37.285 antiInject[7482:630392] /Library/MobileSubstrate/MobileSubstrate.dylib
  2. 复制代码

白名单检测

那么上面的检测只可以检测越狱环境中的代码注入,在非越狱环境中,逆向工程师可以利用yololib工具注入动态库.所以我们可以检索一下自己的应用程序所加载的动态库是否是我们源程序所有

  1. bool HKCheckWhitelist(){
  2. int count = _dyld_image_count();
  3. for (int i = 0; i < count; i++) {
  4. //遍历拿到库名称!
  5. const char * imageName = _dyld_get_image_name(i);
  6. //判断是否在白名单内,应用本身的路径是不确定的,所以要除外.
  7. if (!strstr(libraries, imageName)&&!strstr(imageName, “/var/mobile/Containers/Bundle/Application”)) {
  8. printf(“该库非白名单之内!!\n%s”,imageName);
  9. return NO;
  10. }
  11. }
  12. return YES;
  13. }
  14. 复制代码

其中libraries变量是“白名单”.

小编推荐一个qq群:551346706这个群挺不错的,我就是在群里看到的学习资料写出的这篇文章,这篇文章有源码和视频资料需要的可以了解一下,群里还有各大厂的面试题和算法。还有很多的大牛平时的工作问题也能解决。

PaaS的日志和监控,应该进行怎么处理?

PaaS平台的日志和监控和传统架构的管理方式没有本质区别。日志的获取或采用安装agent、或采用工具导出,业界已经都有很多成熟的产品和案例可以借鉴;监控分两部分,先要解决「监」的问题,同样也需要利用工具抓取信息,然后解决「控」,要么利用自动化运维的模式,要么采用手工的模式,目的其实一样,区别在于成本控制。

PaaS可以从系统、网络、服务、应用监控4个层面入手:

1.系统主要指底层基础资源,如磁盘、CPU、硬件或IaaS等基础资源

2.网络一般采用SDN的方式实现,监控比较复杂,主要有连通性、流量、7层状态码等

3.服务主要是指PaaS中的各种中间件服务服务,比如数据库服务、缓存服务、web应用服务等

4.应用监控是*上层的也是非常重要的,比如应用服务质量、响应时间、请求成功率等

私有云计算和虚拟化之间,主要有什么关系?

虚拟化策略和私有云策略有时让人很困惑,而不同的定义更是让人一头雾水。它们之间*明显的区别在于,虚拟化技术是IT环境这个不动产的固定装置,而云计算作为一种按需服务来提供,分平台即服务、基础设施即服务或软件即服务等几种形式,采用按需付费的模式来提供。

云计算目前是备受关注,英国政府向公共行业开放了Cloudstore,私有行业则出现了一系列重大交易,*近的例子包括德勤会计师事务所和宝洁公司。但是许多企业仍在稳步、更低调地向虚拟化环境转移,泰晤士水务公司(ThamesWater)和梅德韦国民保健信托公司(MedwayNHSTrust)等企业*近在虚拟化方面有所举措。此外,调研机构弗雷斯特公司*近预测,市场对数据虚拟化技术的需求将增长。

企业在考虑自己走哪一条路子时,不得不认真考虑哪一条路能更好地满足自己的业务需求。这可能有一定的难度,尤其是由于这两项技术经常用与业务流程没有多大关系的语言来描述,但是还是有许多因素应该予以考虑。

成本优势的抵消

在这几条之中,成本是*明显的因素。虚拟化方面的成本会比较高,因为它需要投入大量的工作来进行建立和定制,而云服务提供商已经承担了这些成本。后者还通过实用计算模式提供了提高效率、节省成本的优点;按照这种模式,顾客只需要为实际使用的服务付费;但是如果大量使用服务,成本就会增加,开始抵消*初节省成本的优点。

对许多企业来说不太可能是这种情况,但是有时候,自己拥有资产来得更便宜。如果企业需要高度的控制性,那么虚拟化就能带来明显的优势。在自己的数据中心里面保持运营让企业更容易管理和改变自己的IT环境,从而提供了更大强灵活性。

如果企业运行必须针对虚拟化平台来进行调整的许多专门的应用程序,又想对使用技术方面的变化作出响应,这一点很重要。对加大使用远程技术或奉行BYOD(带来自己的设备)策略的企业来说,这可能也是个重大因素。而更大的控制性还与数据安全方面的顾虑有关。

毫无疑问,云服务提供商对这个问题非常重视,它们会提供服务级别协议,从而为它们保管的数据的完整性提供有力保障。但是数据越敏感,焦虑越大,一些企业通过在自己的数据中心保管数据得到的保障就越大,因为它们自己的工作人员每天在数据中心负责安全工作。这种控制还在管理涉及法律和法规问题的风险方面提供了更大的保障。

停机因素

可靠性也是个有争议的话题,很难达成共识。在虚拟化环境下,网络连接中断会导致用户无法访问多台服务器;但是由于广域网链接的云架构出现故障,也会出现类似的问题。但是有理由认为:万一遇到了问题,云计算提供了更大的弹性,提供商可能有更多的办法,以便使用多台服务器,或者改用其他数据中心。此外,云环境中的可扩展性通常更强,一家业务发展迅猛的公司有机会加强数据保管和处理能力,又不需要大笔内部投入所需的那种时间和成本。

这与云提供商提供的短期交易带来的灵活性相一致,有时提供商承诺提供几个月而不是几年有保障的服务,以便迅即响应客户的需求。但是云计算方面的炒作应该不会干扰使用虚拟化的理由。总的来说,云计算不是很明确,依赖一系列价值判断,而这些价值判断取决于企业业务的性质和环境。虚拟化有时被称为是向采用私有云迈出一步的一项技术。但是一些企业在迈出了这一步后可能想停顿一下,看看它是不是满足了自己所需的各个要求。

【iOS】越狱检测

前段时间公司让做了个对越狱设备的检测和拦截,下面是综合自己的开发和网上一些帖子的总结,总体来说做起来还是比较简单的,但是有一个大坑一定要注意!!

一、什么是越狱
越狱:是指针对iPhone操作系统(即iOS系统)限制用户存储读写权限的破解操作。经过越狱的iPhone拥有对系统底层的读写权限,能够让iPhone手机免费使用破解后的App Store软件的程序(相当于盗版)

更详细点说,越狱是指利用iOS系统的某些漏洞,通过指令取得到iOS的root权限,然后改变一些程序使得设备的功能得到加强,突破封闭式环境。

二、越狱优缺点
越狱的好处
1.系统权限很高,可以自己优化系统,可以修改系统文件,可以安装更多拥有高系统权限的软件,实现更多高级功能!例如:与其他设备蓝牙发送文件、短信回执、来电归属地、文件管理、浏览器下载插件、flash插件、内容管理等等。
2.可以安装破解后的软件。
3.可以更换主题、图标、短信铃声等等,打造个性的手机。
4.可以借助第三方文件管理软件灵活的管理系统或者其他文件,比如把iPhone当移动硬盘(u盘)

越狱的害处
对用户
1.费电,越狱后系统会常住一些进程保持越狱的状态。视系统级软件(deb格式)安装的数量,越狱后耗电速度约提升10% ~20%。
2.可能会造成系统不稳定,拥有很高系统权限的同时,也伴随着系统崩溃的危险,这个道理大家能理解吧?你可以修改它,但是你不能保证永远正确的修改它。所以系统级的软件宁缺毋滥,不了解用途的情况下不要乱安装。
3.在新的手机固件版本出来的时候,不能及时的进行更新。每个新版本的固件,都会修复上一个版本的越狱漏洞,使越狱失效。因此如果需要保持越狱后的功能,要等到新的越狱程序发布,才能升级相应的手机固件版本。
4.越狱过程中滋生小BUG,但是不是很影响使用.

对公司,随着iOS系统的逐步完善,越狱机对应用层的攻击也越来越难,譬如:iOS7相比之前系统版本,升级了沙盒机制,封锁了几乎全部应用沙盒可以共享数据的入口。即使在越狱情况下,限制也非常多,大大增加了应用层攻击难度。但是:
用户越狱后,还是可以通过下载一些插件,
譬如:xCon(n00neimp0rtant and Lunatik联合开发)、NZT、tsPretector等,
来篡改设备信息,从而来刷一些商家或公司活动福利,或者利用一些漏洞故弄一些异常来投诉。

三、越狱的检测
对于越狱的判断,想要做到完全检测是非常难的,因为一是苹果在一直修补已知漏洞,所以越狱攻击程序也一直在更改,二是用户可能安装了越狱检测绕过软件(xCon)。
所以我们只要做到在多重越狱检测的基础上,尽可能的提高越狱设备的判定率就行了,常见的检测方法如下:

1. 使用NSFileManager,判断设备上是否安装了常用越狱工具。(容易被hook掉)
2. 使用stat系列函数检测常用越狱工具。(也可能被hook掉)
3. 那就需要检测下stat是否出自系统库。
4. 检测链接动态库(不建议,appStore审核可能不过)
5. *后还可以通过检测程序运行的环境变量。

四、检测方法
使用NSFileManager,判断设备上是否安装了常用越狱工具。
//判断工具安装路径 本期先做成BOOL开关方法
– (BOOL)checkPath
{
BOOL jailBroken = NO;
NSString * cydiaPath = @”/Applications/Cydia.app”;
NSString * aptPath = @”/private/var/lib/apt”;
if ([[NSFileManager defaultManager] fileExistsAtPath:cydiaPath]) {
jailBroken = YES;
}
if ([[NSFileManager defaultManager] fileExistsAtPath:aptPath]) {
jailBroken = YES;
}
return jailBroken;
}
·
上述路径也可替换为以下常见越狱工具路径:
/Library/MobileSubstrate/MobileSubstrate.dylib
/Applications/Cydia.app /var/lib/cydia/
/var/cache/apt /var/lib/apt /etc/apt
/bin/bash /bin/sh
/usr/sbin/sshd /usr/libexec/ssh-keysign /etc/ssh/sshd_config

使用stat系列函数检测常用越狱工具
//防hook NSFileManager的方法 使用stat系列函数检测Cydia等工具,路径同上
– (BOOL)checkCydia
{
struct stat stat_info;
if (0 == stat(“/Applications/Cydia.app”, &stat_info)) {
NSLog(@”Device is jailbroken”);
return YES;
}
return NO;
}

检测stat是否出自系统库
int ret;
Dl_info dylib_info;
int (*func_stat)(const char *,struct stat *) = stat;
if ((ret = dladdr(func_stat, &dylib_info))) {
if (strcmp(dylib_info.dli_fname,”/usr/lib/system/libsystem_kernel.dylib”) != 0) {
jailbroken = YES;
}
}

检测链接动态库,检测是否被链接了异常动态库,但动态库相关Api属于私有Api,调用的话appStore审核会不通过,所以不列举。

检测程序运行的环境变量

//检测当前程序运行的环境变量,防止通过DYLD_INSERT_LIBRARIES注入链接异常动态库,来更改相关工具名称
– (BOOL)checkEnv
{
char *env = getenv(“DYLD_INSERT_LIBRARIES”);
NSLog(@”%s”, env);
if (env) {
return YES;
}
return NO;
}

五、深坑请注意!!
千万不要通过判断是否可以打开 cydia:// 为首的URL Schema 来判断是否越狱,因为你会发现很多App居然注册了这个URL Type !!

【iOS】简述CocoaPods私有库创建流程

简明扼要的概述下CocoaPods私有库的创建过程、

一、创建私有库管理仓库Spec Repo
在git上创建一个仓库 SpecRepo:用来管理私有库.podspec文件
将SpecRepo clone到本地
# pod repo add [Private Repo Name] [GitHub HTTPS clone URL]
1
二、制作podspec文件
1.在git上创建项目仓库 MyProject:用来保存私有库及相应Demo等

%title插图%num

2.将MyProject clone到本地,并添加私有库文件及相应Demo

%title插图%num
3.创建podspec文件

# pod spec create [MyProject]
1
4.编辑podspec

1
5.验证podspec文件是否有效

pod lib lint MyProject.podspec —allow-warnings;
1
6.commit push 到远程 包含以下文件

%title插图%num

三、本地验证测试私有库是否正确
1.新建一个测试Demo
2.直接引入本地私有库

pod ‘MyProject’, :podspec => ‘/Users/jaime/Desktop/MyProject/MyProject.podspec’ #指定podspec文件
1
3.pod 安装后,测试验证私有库功能是否完整准确

四、将.podspec文件提交SpecRepo
pod repo push [SpecRepo] MyProject.podsepc
1
五、pods安装使用私有库
pod search MyProject
pod ‘MyProject’, ‘~> 0.0.1’

使用云存储解决方案,主要有哪些优势?

随需获得存储空间

与直接使用硬盘存储数据不同,云存储的容量可以根据你的需要轻松进行调整。根据你需要在线存储的文件类型和总量,你可以选择适合你的存储配置。如果你只需要存储一些PDF文件,那么你就只需要一小点存储空间就可以了,这可能甚至都不需要你为服务费用。这是因为大部分服务存储厂商都给他们的用户提供了免费的存储空间。如果你欲存储一些大的文件,如视频和图片之类的话,那么你需要升级你的帐户,这样你就可以获得更大的存储空间了。关于云存储的有一件特别好的事情,那就是根据你所需要的空间容量进行调整,适应你的需求。你可以随时升级你的存储帐户,增加你的存储空间。与升级硬件系统来适应你有变化和不断增长的数字化需求相比,这帮你省去了不少的麻烦,且降低了成本开销。

省钱

人们转向云服务的理由其一,是当他们使用互联网服务时可以省钱。例如,RingCentral提供的VoIPPBX服务的成本就很有效,因为他引入了互联网的力量来连接呼叫。云存储服务也是这样的。在你使用互联网进行数据复本保存时,你就节省了成本。使用云存储服务可以从几个方面帮助你省钱。一是,它帮助你消除了使用硬件存储数据的需要。你不必再购买、维护和升级电脑系统、硬件驱动和CD了,就可以进行数据备份。另外一条使用云存储服务省钱的途径是你可以免费使用。只要你所需要的存储空间不超过免费提供的,你就不必向提供商付费,你就可以免费使用。对于大部分个人用户来说,免费的存储空间就足够了。GoogleDrive为用户提供了15GB的免费存储空间,用户可以存储上千个文档和PDF文件。另外,Mega.co.nz给用户提供了免费的50GB存储空间,用户可以在云存储上存储几个相册甚至是一定长度的视频。

随需随用

告别了离开U盘所产生的一些不必要的后果。使用云存储服务可以很容易就访问你的文件,即使你的笔记本电脑或U盘不在身边也可以。只要有网络连接,你就可以使用任何一台电脑、智能手机或移动计算设备来访问甚至编辑那些存储在云上的文件。

以上三点是使用云存储服务*明显的三大的优势,而且云计算是必然的趋势,相信在不久的将来,人们都会逐步走向云端。

企业部署云计算和边缘计算服务,主要有哪些优势?

当涉及到计算时,边缘计算成为了目前流行的话题。这是为什么?边缘计算是一种分散计算能力并将移动到用户和设备访问互联网的端点生成数据的方式。这样可以更好地控制用户体验,并在网络边缘更快地处理数据,例如智能手机和物联网设备等。

由于企业希望扩展其涉及丰富媒体和个性化内容的网站的企业数字渠道策略,因此拥有一个强大的弹性策略至关重要。

部署云计算和边缘计算服务的5大好处

部署云计算和边缘计算服务的组合可以帮助减少意外停机,提高安全性和性能,扩展多云基础设施的优势,加快应用程序的开发和交付,并改善用户体验。

1.减少意外停机

用户不会容忍在访问网站或系统服务时遇到中断或宕机。不幸的是,根据咨询机构Forrester公司*近进行的一项调查,只有46%的公司拥有技术连续性或安全计划,这意味着超过一半的企业基础设施容易出现意外停机。根据这项研究显示,近一半的公司每月至少有一次停机时间,这无疑给他们的客户和业务带来大量损失。

这就是为什么现在几乎每个人都想要达到难以捉摸的“5个9”(99.999%)的可用性的原因,而这意味着每年只有五分钟的停机时间。

不可用的网络连接,严重的延迟、安全攻击持续造成高达50%的意外停机时间。边缘服务可以通过监视用户和资源之间的连接来帮助组织实现这一目标,并实时处理和调整任何故障。

2.提高安全性和性能

在足球比赛中,有一个术语被称为“设置边缘”。这个术语主要用于防守,但它同样适用于进攻。在防守端,防守队员的任务是“设置边缘”或者进行外线进攻,以确保对方选手不能在禁区外线长传。同样,在进攻端,一名进攻球员必须通过阻挡防守球员来“设定边缘”,以便让控球运动员在外线获得更大的收益。

在某些方面,边缘计算的工作原理就像在足球比赛中设置边缘一样。通过提供使信息更贴近客户的服务,企业可避免业务中断,提高性能,实现更安全的连接,并改善整体用户体验。边缘服务将自动引导流量,以确保网络上快速安全地交付。

边缘服务对帮助组织提供性能和安全功能对于面向内部应用程序(如CRM和ERP系统)以及面向客户的应用程序变得至关重要。企业必须将用户引导至适当的网络和基础设施,以便他们能够连接到适当的服务。使用边缘服务将控制点移近用户可以增强安全性,并在需要时帮助确保符合法规和隐私规范。

此外,在边缘计算需要更少的延迟,并且在使用物联网设备时不需要连续的连接,这不会影响弹性。

3.扩展多云的好处

如今,更多应用程序依靠多云架构提供灵活性、弹性和改进的边缘性能。分析师的调查研究将商业智能和报告应用程序、物联网应用程序、营销自动化应用程序列为*有可能使用多云架构的应用程序。

此外,多云与边缘服务(如托管域名系统解决方案)结合使用可以提高弹性。域名系统(DNS)不仅有助于应用程序性能和网络弹性,还可以优化Web应用程序性能,并管理多云环境中的流量。

4.加快应用程序交付和开发

边缘服务还会影响应用程序的端到端交付,特别是当采用DeVoP实践时,将应用程序开发人员与操作人员结合起来变得更加普遍。借助DevOps,开发人员越来越多地负责开发和部署或软件交付生命周期的更多部分,其中包括将工作转移到边缘的应用程序。

这意味着开发人员需要高效地构建将处理转移到边缘并支持边缘服务的应用程序。总的来说,云计算已成为应用程序开发和交付代理的一个具有吸引力的目标,边缘服务代表了创新机会。

5.改善用户体验

边缘计算可以通过移动处理、数据和服务来确保更好的用户体验,在这些处理,数据和服务中,它们可以*好地满足用户的需要。

增加正常运行时间、弹性、性能和一致的服务也可改善客户体验。此外,由于边缘服务不仅使数据更贴近用户,而且可以优化用户体验,并提供丰富的内容,因此客户越来越希望获得更多个性化体验,这些体验可以在边缘提供。

此外,由于用户需要对查询作出更快的响应,因为数据在数据中心或云计算之外进行管理,因此边缘服务可以满足客户要求,这可以为客户提供更具交互性和身临其境的体验。

如今,为客户服务是每个企业的首要任务。他们比以往任何时候都更能够获得在线信息,并对为他们提供服务的企业的卓越经验抱有很高的期望。

因此,企业应考虑实施完整的云计算战略,其中包括边缘服务和云计算,以获得急需的弹性。

部署云计算基础设施,我们主要面临哪些挑战

第1个挑战:功率密度增加

高功率密度区域势必会面临散热难的挑战。在云计算环境中,虚拟服务器经常成群成组的排布在一起,这就可能产生“热点”。优先采取的办法是将较高功率密度的设备迁移至特定的机柜或机柜行,与较低功率密度的设备分区布局。这样的高密度“区域部署”具有更高的可预测性,并且可以确保每机柜的功率密度实现*大。

第2个挑战:PUE恶化

虚拟化可以大幅降低服务器能耗。但是,如果供电和制冷基础设施仍保持未进行虚拟化前的状态,则会导致PUE(能源利用率)恶化。以可扩展供电和制冷解决方案,通过对新负载“按需规划”,可显着降低这些低效表现。

第3个挑战:宕机风险上升

云计算数据中心的负载可能因时间和位置的不同而变化。经过高度虚拟化的云计算数据中心的负载波动可能更大。在云计算环境中,使用可预测的管理工具是保持数据中心精简、高效的安全方法。实时配合虚拟机(VM)管理器,确保供电量和制冷量与动态负载高效匹配。

第4个挑战:采用不必要的冗余等级

云计算数据中心配有高级别的IT容错系统,这可能会降低供电和制冷基础设施的冗余需求。将物理基础设施冗余配合虚拟化云计算环境容错特性就是按需规划的另一种形式,可以大幅降低成本。

从事云计算专业,需要了解的几个概念

虽然云计算的定义很宽泛,但是对于使用这项技术的那些人来说,想充分了解对于项目成功很重要的概念并非易事。以下是考虑迁移到云计算的那些人应该了解的五个重要概念–或者可能完全是误解。

1、云计算不是虚拟化。这似乎是个普遍的误解,所以值得说明一下:虚拟化服务器不构成云。云计算意味着自动配置资源、基于用户的计费模式、高级多租户架构以及远胜过大多数虚拟化解决方案的能力。许多人应该牢记这一点,时不时地提醒自己。

2、云计算需要应用编程接口(API)。那些创建网站、称之为”云站点”的人要明白:云计算的价值其一方面在于通过API访问及使用核心的云服务。这既适用于公有云,又适用于私有云。要是没有API,它根本就不是云。

3、迁移到云并不能解决糟糕的做法。并不是说你迁移到云计算后,糟糕的架构或糟糕的应用软件设计自动就会得到解决。你需要在迁移之前解决掉那些问题。

4、无论是不是云,安全都要牢记在心。虽然许多人出于安全方面的担忧而不敢实施云计算项目,但云计算实际上与大多数内部部署的系统一样安全,甚至来得更安全。除了考虑到数据和应用程序的需求外,你在设计系统时还必须考虑到安全需求,然后利用相应的技术支持那些需求。传统系统可以这么做,公共云或私有云同样可以这么做。

5、没有什么所谓的”快速云”解决方案。虽然许多公司在销售所谓的”盒子中的云”(cloud-in-a-box)这类解决方案,但很少有即开即用的方案在不需要大量定制和集成工作以便从中获取一些价值的情况下,就适合你的用户计算要求。这方面充斥着太多的泡沫。

【iOS】category重写方法的调用

前两天工程中,出现了一个类的两个分类(自己实现了一个,第三方SDK里有一个),同时实现了一个方法名相同的方法,当时就产生了一个疑问,当实际调用时调的是哪个分类的方法呢?

一、category重写主类方法
首先先来看看这一点,相信大部分人已经知道,如果一个类的分类重写了这个类的方法后,那么这个类的这个方法将失效,起作用的将会是分类的那个重写方法,在分类重写的时候Xcode也会给出相应警告:分类实现将会替代主类实现

那么原方法失效,分类方法生效的原理是?

想弄清这点先来看一下类的初始化,首先oc是动态语言,建立在runtime 的基础上,同样类的初始化也是动态的,根类NSObject 的+load 和+initilize两个方法,用于类的初始化,我们这里要着重看的是+load方法:

+load 方法是当类或分类被添加到 Objective-C runtime 时被调用的,实现这个方法可以让我们在类加载的时候执行一些类相关的行为。子类的 +load 方法会在它的所有父类的 +load 方法执行之后执行,而分类的 +load 方法会在它的主类的 +load 方法执行之后执行。但是不同的类之间的 +load 方法的调用顺序是不确定的。

原因就在这里,因为加载顺序是父类先+load,然后子类+load,然后分类+load,那么如果分类重写子类方法:首先子类+load,将方法添加到类的方法列表methodLists,然后分类+load,将重写的方法添加到方法列表中,但是这里存在几点疑问:
1. 方法列表methodLists里是否会有两个SEL相同的方法?
2. 如果会有,这两个方法在方法列表中的顺序是怎样的?(顺序决定哪个被调用)

下面来求证一下:

#import “TestCategory.h”
/*主类实现*/
@implementation TestCategory
– (void)newMethod {
NSLog(@”主类”);
}
@end

#import “TestCategory+add.h”
/*分类一实现*/
@implementation TestCategory (add)
– (void)newMethod {
NSLog(@”分类一”);
}
@end

#import <objc/runtime.h>
#import “TestCategory.h”
@implementation ViewController

– (void)viewDidLoad {
[super viewDidLoad];

id LenderClass = objc_getClass(“TestCategory”);
unsigned int outCount, i;
//获取实例方法列表
Method *methodList = class_copyMethodList(LenderClass, &outCount);
for (i=0; i<outCount; i++) {
Method method = methodList[i];
NSLog(@”instanceMethod:%@”, NSStringFromSelector(method_getName(method)));
}

//调用一下
TestCategory *tCategory = [[TestCategory alloc]init];
[tCategory newMethod];
}

看输出:

2017-07-19 21:38:13.593 TestRuntimeProperty[27827:1306334] instanceMethod:newMethod
2017-07-19 21:38:13.593 TestRuntimeProperty[27827:1306334] instanceMethod:newMethod
2017-07-19 21:38:13.594 TestRuntimeProperty[27827:1306334] 分类一

可见:
1. 方法列表里会存在两个SEL相同的方法。
2. 实际调用时,调用的是后添加的方法,即后添加的方法在方法列表methodLists的这个数组的顶部

答案已经很明确了:后+load的类的方法,后添加到方法列表,而这时的添加方式又是插入顶部添加,即[methodLists insertObject:category_method atIndex:0]; 所以objc_msgSend遍历方法列表查找SEL 对应的IMP时,会先找到分类重写的那个,调用执行。然后添加到缓存列表中,这样主类方法实现永远也不会调到。

(注:methodLists和method的结构定义可以看下我上篇文章-【iOS】Runtime解读)

二、多个category实现同一个方法
但是如果多个分类同时重写同一个方法,执行顺序又是怎样的呢?

答案是:对于多个分类同时重写同一个方法,Xcode在运行时是根据buildPhases->Compile Sources里面的顺序从上至下编译的,那么很明显就像子类和分类一样,后编译的后load,即后添加到方法列表,所以后编译的分类,方法会放到方法列表顶部,调用的时候先执行。

添加代码验证一下:

#import “TestCategory+addAgain.h”
/*分类二实现*/
@implementation TestCategory (addAgain)
– (void)newMethod {
NSLog(@”分类二”);
}
@end

看输出:

2017-07-19 22:18:13.593 TestRuntimeProperty[28385:1331972] instanceMethod:newMethod
2017-07-19 22:18:13.593 TestRuntimeProperty[28385:1331972] instanceMethod:newMethod
2017-07-19 21:18:13.593 TestRuntimeProperty[28385:1331972] instanceMethod:newMethod
2017-07-19 22:18:13.594 TestRuntimeProperty[28385:1331972] 分类一

结果输出仍然是分类一,那就说明”TestCategory+add.h”在buildPhases->Compile Sources里面的顺序是靠下的,看下buildPhases的确如此:

总结一句话:类的加载顺序,决定方法的添加顺序,调用的时候,后添加的方法会先被找到,所以调用的始终是后加载的类的方法实现。