OC中通过Runtime对全局POST请求进行加密

本文着重介绍的事如何通过Runtime对全局POST请求进行拦截和修改请求体的方法,不是着重介绍加密算法的细节,需要算法细节的请看其他文章吧 谢谢。
最近一直在搞Safencrypt安全系统,之前文章也提过,这套系统就是能够对所有的网络请求进行加密,保证数据传输过程的安全性。为了不让开发者注意到自动加密的细节,决定采用自动拦截所有请求进行加密的方式,有这个想法的时候我第一时间想到的就是NSURLProtocol,经过好一番研究,发现在NSURLProtocol的- startLoading方法中根本拿不到NSURLRequest的HTTPBody,更别提怎么对其进行加密了,翻了翻苹果的开发者文档,文中确实有说过:在NSURLProtocol中拿不到NSURLSession使用的request HTTPBody,这么做的原因是防止HTTPBody过大而引发的内存问题。Stack Overflow上看了好多相关的帖子,各路大神也好多在研究,不过没有太好的解决办法。于是只能采用变通的办法了:在设置请求体的时候就对设置的内容进行加密。
做过JavaWeb的朋友肯定第一时间会想到AOP,面向切面编程,我也如此,就用AOP的思想去做,在iOS中实现也是非常简单——runtime。通过翻看源码可知,

@property (nullable, readonly, copy) NSData *HTTPBody;

NSURLRequest的HTTPBody属性是readonly的,我们常用的setHTTPBody方法是属于NSMutableURLRequest的

@property (nullable, copy) NSData *HTTPBody;

于是决定对NSMutableURLRequest动手。
由于是@property,所以知道其默认的set方法为

- (void)setHTTPBody: (NSData *)data;

我们首先创建与这个函数参数返回值相同的IMP别名定义:

typedef void (*_VIMP) (NSMutableURLRequest *,SEL,NSData *);

然后使用这个类型创建变量,方便稍后将系统本身的setHTTPBody函数实现存放到这里

static _VIMP _old_set_http_body_imp; // 系统setHTTPBody的IMP存储

接下来创建一个我们自己的setHTTPBody函数实现,在实现中我们把用户传入的NSData进行加密,然后把加密后的NSData传给系统的setHTTPBody函数实现中:

// safencrypt-setHTTPBody方法
void safencryptSetHTTPBody(NSMutableURLRequest *SELF , SEL _cmd, NSData *data){
    if (data != NULL) {
        _old_set_http_body_imp(SELF ,_cmd , [SAES encrypt: data]);
    }
    else {
        _old_set_http_body_imp(SELF ,_cmd , data);
    }
}

上面的代码块中[SAES encrypt: data]是我自己的加密工具类,实际就是将未加密的NSData传入,返回AES加密后的NSData,这里就不列出算法细节了。
接下来,我们在ViewController的viewDidLoad函数里面进行替换操作,你也可以选择在其他地方进行替换,选择一个合适自己的场景:

    // 获取NSMutableURLRequest类
    Class cls = NSClassFromString(@"NSMutableURLRequest");
    // 获取系统setHTTPBody的原有方法selector
    SEL set_http_body_sel = @selector(setHTTPBody:);
    // 根据selector获取方法实现
    Method oldMethod = class_getInstanceMethod(cls,  set_http_body_sel);
    // 获取原来系统的实现,先保存起来,以备safencryptSetHTTPBody中调用
    _old_set_http_body_imp = method_getImplementation(oldMethod);
    // 替换系统的setHTTPBody方法为SafencryptSetHTTPBody方法
    class_replaceMethod(cls, set_http_body_sel, (IMP)safencryptSetHTTPBody, NULL);

这段代码每一行都有对应的注释,如果还是不懂可以参考一下几篇文章对runtime相关的讲解:
https://yq.aliyun.com/articles/3063
http://www.cocoachina.com/ios/20150717/12623.html
http://www.cocoachina.com/ios/20150120/10959.html

你可能感兴趣的:(OC中通过Runtime对全局POST请求进行加密)