AFSecurityPolicy 安全策略
2021-11-29 本文已影响0人
helinyu
PS: 小结
- AFSSLPinningModeCertificate :证书模式 1)判断信任链上的公钥是否有交集 2)判断授权是否有效等信息
- AFSSLPinningModePublicKey : 公钥模式:只是 判断信任链上的公钥是否有交集
// 这个方法就是简单的判断两个对象是否相等
static BOOL AFSecKeyIsEqualToKey(SecKeyRef key1, SecKeyRef key2) {
return [(__bridge id)key1 isEqual:(__bridge id)key2];
}
通过证书数据获取公钥
static id AFPublicKeyForCertificate(NSData *certificate) {
id allowedPublicKey = nil;
// 这几个对象要理解清楚
SecCertificateRef allowedCertificate; // 允许证书
SecPolicyRef policy = nil; // 安全策略
SecTrustRef allowedTrust = nil; // 信任上下文
SecTrustResultType result; // 信任结果
// 通过证书数据获取一个证书对象
allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificate);
__Require_Quiet(allowedCertificate != NULL, _out);
policy = SecPolicyCreateBasicX509(); // X509的格式策略
__Require_noErr_Quiet(SecTrustCreateWithCertificates(allowedCertificate, policy, &allowedTrust), _out);
// 证书数据、策略 创建一个信任对象
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
__Require_noErr_Quiet(SecTrustEvaluate(allowedTrust, &result), _out);
// 对信任对象进行评估, 是否是信任的,如果信任的
#pragma clang diagnostic pop
// 如果信任的就获取公钥返回
allowedPublicKey = (__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust);
_out:
if (allowedTrust) {
CFRelease(allowedTrust);
}
if (policy) {
CFRelease(policy);
}
if (allowedCertificate) {
CFRelease(allowedCertificate);
}
return allowedPublicKey;
}
//服务器信任是否有效
// 传入的是服务器的信任对象serverTrust,, 其实就是证书的信任对象
static BOOL AFServerTrustIsValid(SecTrustRef serverTrust) {
BOOL isValid = NO;
SecTrustResultType result;
NSError *error;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
__Require_noErr_Quiet(SecTrustEvaluate(serverTrust, &result), _out);
// 检测信任对象的结果
#pragma clang diagnostic pop
isValid = (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);
_out:
return isValid;
}
// 获取一个证书的信任链
static NSArray * AFCertificateTrustChainForServerTrust(SecTrustRef serverTrust) {
CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust); // 证书(链)的数目
NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount]; //数据
for (CFIndex i = 0; i < certificateCount; i++) {
SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i);
// 通过所以,获取帧数的数据
[trustChain addObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)];
}
return [NSArray arrayWithArray:trustChain];
}
// 获取信任的公钥链
static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
SecPolicyRef policy = SecPolicyCreateBasicX509(); // X509格式的安全策略
CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust); // 证书数目
NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount]; //信任链
for (CFIndex i = 0; i < certificateCount; i++) { // 通过遍历,获取证书链中的公钥链
SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i); // 获取信任证书
SecCertificateRef someCertificates[] = {certificate}; // 证书
CFArrayRef certificates = CFArrayCreate(NULL, (const void **)someCertificates, 1, NULL); // 证书
SecTrustRef trust;
__Require_noErr_Quiet(SecTrustCreateWithCertificates(certificates, policy, &trust), _out);
SecTrustResultType result;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
__Require_noErr_Quiet(SecTrustEvaluate(trust, &result), _out);
#pragma clang diagnostic pop
[trustChain addObject:(__bridge_transfer id)SecTrustCopyPublicKey(trust)];
_out:
if (trust) {
CFRelease(trust);
}
if (certificates) {
CFRelease(certificates);
}
continue;
}
CFRelease(policy);
return [NSArray arrayWithArray:trustChain];
}
AFSecurityPolicy 对象
// 获取bundle下面的证书
+ (NSSet *)certificatesInBundle:(NSBundle *)bundle {
NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."];
NSMutableSet *certificates = [NSMutableSet setWithCapacity:[paths count]];
for (NSString *path in paths) {
NSData *certificateData = [NSData dataWithContentsOfFile:path];
[certificates addObject:certificateData];
}
return [NSSet setWithSet:certificates];
}
// 默认安全策略
+ (instancetype)defaultPolicy {
AFSecurityPolicy *securityPolicy = [[self alloc] init];
securityPolicy.SSLPinningMode = AFSSLPinningModeNone;
return securityPolicy;
}
// 定位模式的策略
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode {
NSSet <NSData *> *defaultPinnedCertificates = [self certificatesInBundle:[NSBundle mainBundle]]; // 证书的数据
return [self policyWithPinningMode:pinningMode withPinnedCertificates:defaultPinnedCertificates];
}
// 获取策略, 定位模式、 定位证书
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet *)pinnedCertificates {
AFSecurityPolicy *securityPolicy = [[self alloc] init];
securityPolicy.SSLPinningMode = pinningMode;
[securityPolicy setPinnedCertificates:pinnedCertificates];
return securityPolicy;
}
- (instancetype)init {
self = [super init];
if (!self) {
return nil;
}
self.validatesDomainName = YES; // 有效的域名
return self;
}
// 设置定位证书
// 其实就是设置公钥
- (void)setPinnedCertificates:(NSSet *)pinnedCertificates {
_pinnedCertificates = pinnedCertificates;
if (self.pinnedCertificates) { // 定位证书
NSMutableSet *mutablePinnedPublicKeys = [NSMutableSet setWithCapacity:[self.pinnedCertificates count]];
for (NSData *certificate in self.pinnedCertificates) {
id publicKey = AFPublicKeyForCertificate(certificate); // 获取证书的公钥
if (!publicKey) {
continue;
}
[mutablePinnedPublicKeys addObject:publicKey];
}
self.pinnedPublicKeys = [NSSet setWithSet:mutablePinnedPublicKeys];
} else {
self.pinnedPublicKeys = nil;
}
}
*重点方法*
// serverTrust 服务器的信任对象
// domain : 域名
// 遍历从当前的所有证书中获取证书
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
forDomain:(NSString *)domain
{
// 不合格的检测
if (domain && self.allowInvalidCertificates && self.validatesDomainName && (self.SSLPinningMode == AFSSLPinningModeNone || [self.pinnedCertificates count] == 0)) {
// https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/OverridingSSLChainValidationCorrectly.html
// According to the docs, you should only trust your provided certs for evaluation.
// Pinned certificates are added to the trust. Without pinned certificates,
// there is nothing to evaluate against.
//
// From Apple Docs:
// "Do not implicitly trust self-signed certificates as anchors (kSecTrustOptionImplicitAnchors).
// Instead, add your own (self-signed) CA certificate to the list of trusted anchors."
NSLog(@"In order to validate a domain name for self signed certificates, you MUST use pinning.");
return NO;
}
NSMutableArray *policies = [NSMutableArray array];
if (self.validatesDomainName) {
[policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
// 域名有效, 通过域名创建SSL验证
} else {
[policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()]; // X509 策略
}
SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies); // 设置信任对象
if (self.SSLPinningMode == AFSSLPinningModeNone) {
// 这个服务器判断有效
return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust);
} else if (!self.allowInvalidCertificates && !AFServerTrustIsValid(serverTrust)) {
return NO;
}
switch (self.SSLPinningMode) {
case AFSSLPinningModeCertificate: { // 证书模式
NSMutableArray *pinnedCertificates = [NSMutableArray array];
// 通过二进制获取对应的证书对象
for (NSData *certificateData in self.pinnedCertificates) {
[pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
}
// 设置证书的授权信任
// 这个还要判断授权
SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
if (!AFServerTrustIsValid(serverTrust)) {
return NO;
}
// obtain the chain after being validated, which *should* contain the pinned certificate in the last position (if it's the Root CA)
// 判断当前的目标证书是否在信任的证书链的公钥上 , 俩决定成功与否
NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust); // 获取信任链
for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
if ([self.pinnedCertificates containsObject:trustChainCertificate]) {
return YES;
}
}
return NO;
}
// 这个是指验证这个公钥链是否有交集就可以了
case AFSSLPinningModePublicKey: { // 公钥模式
NSUInteger trustedPublicKeyCount = 0;
NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust);
for (id trustChainPublicKey in publicKeys) { // 指定信任的公钥链
for (id pinnedPublicKey in self.pinnedPublicKeys) { // 目标的公钥链
if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey)) {
trustedPublicKeyCount += 1;
}
}
}
return trustedPublicKeyCount > 0;
}
default:
return NO;
}
return NO;
}
NSCoding与NSSecureCoding相比于NSSecureCoding 更安全。防止替换攻击,保证你读到的数据正是你写入的数据