Implement actual policy

This commit is contained in:
James Magahern
2021-10-21 13:24:58 -07:00
parent 70486c49de
commit fc7380ed21
6 changed files with 109 additions and 7 deletions

View File

@@ -12,6 +12,32 @@
@implementation SBRScriptPolicy
+ (NSSet<NSString *> *)_commonCDNOrigins {
static dispatch_once_t onceToken;
static NSSet<NSString *> *whitelist = nil;
dispatch_once(&onceToken, ^{
whitelist = [NSSet setWithArray:@[
// JSDelivr: Used by bootstrap
@"cdn.jsdelivr.net",
// SourceForge
@"fsdn.net",
// Open Source CDNs
@"cdnjs.com",
@"osscdn.com",
// JQuery
@"code.jquery.com",
// Bootstrap
@"bootstrapcdn.com",
]];
});
return whitelist;
}
+ (NSString *)titleForPolicyType:(SBRScriptOriginPolicyType)policyType
{
switch (policyType) {
@@ -118,4 +144,62 @@
[coder encodeObject:[NSNumber numberWithInteger:_policyType] forKey:@"policyType"];
}
- (BOOL)allowsEmbeddedJavaScript
{
return _policyType > SBRScriptOriginPolicyTypeAlpha;
}
- (BOOL)allowsExternalJavaScriptResourceOrigin:(NSString *)resourceOrigin
{
switch (_policyType) {
case SBRScriptOriginPolicyTypeAlpha:
// No scripts allowed whatsoever.
return NO;
case SBRScriptOriginPolicyTypeBravo:
// Only allows on-page scripts, no external scripts whatsoever.
return NO;
case SBRScriptOriginPolicyTypeCharlie:
// Only allow scripts from the exact same origin as the host.
return [_origin isEqualToString:resourceOrigin];
case SBRScriptOriginPolicyTypeDelta: {
// Allow scripts from common CDNs, or CDNs that *appear* to belong to the host.
if ([[[self class] _commonCDNOrigins] containsObject:resourceOrigin]) {
return YES;
}
BOOL looksLikeCDN = NO;
NSArray<NSString *> *hostOriginComponents = [_origin componentsSeparatedByString:@"."];
if ([hostOriginComponents count] > 1) {
// Assume our "family" name is just before the TLD.
NSString *hostFamilyName = [hostOriginComponents objectAtIndex:(hostOriginComponents.count - 2)];
looksLikeCDN = [resourceOrigin containsString:hostFamilyName];
if (!looksLikeCDN) {
NSArray<NSString *> *resourceOriginComponents = [resourceOrigin componentsSeparatedByString:@"."];
if ([resourceOriginComponents count] > 1) {
NSString *resourceFamilyName = [resourceOriginComponents objectAtIndex:(resourceOriginComponents.count - 2)];
// Check and see if the subdomain is "cdn", but also make sure we're not accidentally allowing an ad network CDN.
looksLikeCDN = [[resourceOriginComponents firstObject] isEqualToString:@"cdn"];
BOOL looksLikeAdNetwork = (
[resourceFamilyName hasSuffix:@"ad"] ||
[resourceFamilyName hasSuffix:@"ads"] ||
[resourceFamilyName containsString:@"analy"] // "analy-tics"
);
looksLikeCDN = looksLikeCDN && !looksLikeAdNetwork;
NSLog(@"SBRProcessPlugin: [%@] CDN:%@ AD:%@", resourceOriginComponents, looksLikeCDN ? @"YES" : @"NO", looksLikeAdNetwork ? @"YES" : @"NO");
}
}
}
return looksLikeCDN;
}
case SBRScriptOriginPolicyTypeEcho:
// Anything goes.
return YES;
}
}
@end