URL加载系统之四:认证与TLS链验证

一个NSURLRequest对象经常会遇到认证请求,或者需要从其所连接的服务端请求证书。当需要认证请求时,NSURLConnection、NSURLSession和NSURLDownload类会通知它们的代理对象,以便能正确地做处理。不过需要注意的是,URL加载系统只有在服务端响应包含WWW-Authenticate头时才会调用代理来处理认证请求,而类似于代理认证和TLS信任验证这样的认证类型则不需要这个头。

确定如何响应一个认证请求

如果一个NSURLRequest对象需要认证时,则认证请求方式取决于使用的对象的类型:

如果请求是与NSURLSession对象关联,则所有认证请求都会传递给代理,而不考虑认证的类型。

如果请求是与NSURLConnection或NSURLDownload对象,则对象的代理接收一个connection:canAuthenticateAgainstProtectionSpace: (或者 download:canAuthenticateAgainstProtectionSpace:) 消息。这允许代理对象在尝试再次认证前分析服务端的属性,包括协议和认证方法。如果我们的代理对象不准备认证服务端的受保护空间,则返回NO,且系统尝试使用用户的keychain的信息进行认证。

如果NSURLConnection或NSURLDownload的代理对象没有实现connection:canAuthenticateAgainstProtectionSpace: (或者 download:canAuthenticateAgainstProtectionSpace:)方法,且保护空间使用客户端证书认证或服务端信任认证,则系统假设我们返回NO。而对象其它所有类型,系统都返回YES。

下一步,如果我们的代理对象同意处理认证,但是没有有效的证书(不管是作为请求URL的一部分或者在NSURLCredentialStorage中共享),则代理以收到以下消息:

URLSession:didReceiveChallenge:completionHandler:2. URLSession:task:didReceiveChallenge:completionHandler:3. connection:didReceiveAuthenticationChallenge:4. download:didReceiveAuthenticationChallenge:

为了让连接能够继续,则代理对象有三种选择:

提供认证证书

尝试在没有证书的情况下继续

取消认证查询

为了确保操作的正确流程,传递给这些方法的NSURLAuthenticationChallenge实例会包含一些信息,包括是什么触发了认证查询、查询的尝试次数、任何先前尝试的证书、请求证书的NSURLProtectionSpace对象,及查询的发送者。

如果认证请求事先尝试认证且失败了(如用户在服务端修改了密码),我们可以通过在认证请求调用proposedCredential来获取尝试凭据。代理可以使用这些证书来填充一个显示给用户的话框。

调用认证请求的previousFailureCount可以返回身份验证尝试次数,这些尝试包括不同认证协议的尝试请求。代理可以将这些方法提供给用户,以确定先前提供的证书是否失败,或限制最大认证尝试次数。

响应认证请求

前面说过三种响应我们响应connection:didReceiveAuthenticationChallenge:代理方法的方式,我们将逐一介绍:

提供证书

为了进行认证,程序需要使用服务端期望的认证信息创建一个NSURLCredential对象。我们可以调用authenticationMethod来确定服务端的认证方法,这个认证方法是在提供的认证请求的保护空间中。NSURLCredential支持一些方法:

HTTP基本认证(NSURLAuthenticationMethodHTTPBasic):需要用户名和密码。提示用户输入必要信息并使用credentialWithUser:password:persistence:方法创建一个NSURLCredential对象。

HTTP数字认证(NSURLAuthenticationMethodHTTPDigest):类似于基本认证,需要用户名和密码。提示用户输入必要信息并使用credentialWithUser:password:persistence:方法创建一个NSURLCredential对象。

客户端证书认证(NSURLAuthenticationMethodClientCertificate): 需要系统标识和所有服务端认证所需要的证书。然后使用credentialWithIdentity:certificates:persistence:来创建一个NSURLCredential对象。

服务端信任认证(NSURLAuthenticationMethodServerTrust)需要一个由认证请求的保护空间提供的信任。使用credentialForTrust:来创建一个NSURLCredential对象。

在创建NSURLCredential对象后

对于NSURLSession,使用提供的完成处理block将该对象传递给认证请求发送者

对于NSURLConnection和NSURLDownload,使用useCredential:forAuthenticationChallenge:方法将对象传递给认证请求发送者。

尝试在没有证书的情况下继续

如果代理选择不提供证书,可以尝试继续操作:

对于NSURLSession,传递下面的值给完成处理block: NSURLSessionAuthChallengePerformDefaultHandling:处理请求。尽管代理没有提供代理方法来处理认证请求 NSURLSessionAuthChallengeRejectProtectionSpace:拒绝请求。依赖于服务端响应允许的认证类型,URL加载类可能多次调用这个代理方法。

对于NSURLConnection和NSURLDownload,在[challenge sender]中调用continueWithoutCredentialsForAuthenticationChallenge:。

依赖于协议的实现,这种处理方法可能会导致连接失败而以送connectionDidFailWithError:消息,或者返回可选的不需要认证的URL内容。

取消连接

代理可以选择取消认证请求

对于NSURLSession,传递NSURLSessionAuthChallengeCancelAuthenticationChallenge给完成处理block

对于NSURLConnection和NSURLDownload,在[challenge sender]中调用cancelAuthenticationChallenge:。代理接收connection:didCancelAuthenticationChallenge:消息,以提供用户反馈的机会。

下面的代码演示了使用用户名和密码创建NSURLCredential对象来响应认证请求

-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge

{

if ([challenge previousFailureCount] == 0)

{

NSURLCredential *newCredential;

newCredential = [NSURLCredential credentialWithUser:[self preferencesName] password:[self preferencesPassword] persistence:NSURLCredentialPersistenceNone];

[[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];

}

else

{          [[challenge sender] cancelAuthenticationChallenge:challenge];          // inform the user that the user name and password          // in the preferences are incorrect        [self showPreferencesCredentialsAreIncorrectPanel:self];        }

}

如果代理没有实现connection:didReceiveAuthenticationChallenge:,而请求需要认证,则有效的证书必须位于URL证书存储中或作为请求URL的一部分。如果证书无效或者认证失败,则底层实现会发送一个continueWithoutCredentialForAuthenticationChallenge:消息。

执行自定义TLS链验证

在NSURL系统的AIP中,TLS链验证由应用的认证代理方法来处理,但它不是提供证书给服务端以验证用户,而是在TLS握手的过程中校验服务端提供的证书,然后再告诉URL加载系统是否应该接受还是拒绝这些证书。

如果需要以非标准的方法(如接收一个指定的自标识的证书用于测试)来执行链验证,则应用必须如下处理:

对于NSURLSession,实现URLSession:didReceiveChallenge:completionHandler:和URLSession:task:didReceiveChallenge:completionHandler:代理方法。如果实现了两者,由会话级别的方法负责处理认证。

对于NSURLConnection和NSURLDownload,实现connection:canAuthenticateAgainstProtectionSpace:和download:canAuthenticateAgainstProtectionSpace:方法,如果保护空间有一个NSURLAuthenticationMethodServerTrust类型的认证,则返回YES。然后,实现connection:didReceiveAuthenticationChallenge:或download:didReceiveAuthenticationChallenge:方法来处理认证。

在认证处理代理方法中,我们需要确认认证保护空间是否有NSURLAuthenticationMethodServerTrust类型的认证,如果有,则从保护空间获取serverTrust信息。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容