mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-09-03 20:55:08 +00:00
fix(sanitization): update regex for html sanitization
This commit is contained in:
@@ -987,20 +987,28 @@ static int cssEscapingCount;
|
||||
// Remove javascript:
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"j[\\s\\u200B	

\\\\0]*a[\\s\\u200B	

\\\\0]*v[\\s\\u200B	

\\\\0]*a[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*c[\\s\\u200B	

\\\\0]*r[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*p[\\s\\u200B	

\\\\0]*t[\\s\\u200B	

\\\\0]*:"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];
|
||||
result = [NSString stringWithString: newResult];
|
||||
// loop until stable: a single pass lets nested tokens reconstruct
|
||||
// the scheme, e.g. "javajavascript:script:" -> "javascript:"
|
||||
while ([regex numberOfMatchesInString:result options:0 range:NSMakeRange(0, [result length])] > 0) {
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];
|
||||
result = [NSString stringWithString: newResult];
|
||||
}
|
||||
|
||||
// Remove vbscript:
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"v[\\s\\u200B	

\\\\0]*b[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*c[\\s\\u200B	

\\\\0]*r[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*p[\\s\\u200B	

\\\\0]*t[\\s\\u200B	

\\\\0]*:"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];
|
||||
result = [NSString stringWithString: newResult];
|
||||
while ([regex numberOfMatchesInString:result options:0 range:NSMakeRange(0, [result length])] > 0) {
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];
|
||||
result = [NSString stringWithString: newResult];
|
||||
}
|
||||
|
||||
// Remove livescript:
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"l[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*v[\\s\\u200B	

\\\\0]*e[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*c[\\s\\u200B	

\\\\0]*r[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*p[\\s\\u200B	

\\\\0]*t[\\s\\u200B	

\\\\0]*:"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];
|
||||
result = [NSString stringWithString: newResult];
|
||||
while ([regex numberOfMatchesInString:result options:0 range:NSMakeRange(0, [result length])] > 0) {
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];
|
||||
result = [NSString stringWithString: newResult];
|
||||
}
|
||||
|
||||
// Remove <script
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"<[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*c[\\s\\u200B	

\\\\0]*r[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*p[\\s\\u200B	

\\\\0]*t"
|
||||
@@ -1032,28 +1040,14 @@ static int cssEscapingCount;
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"</for*"];
|
||||
result = [NSString stringWithString: newResult];
|
||||
|
||||
// Remove onload
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"onload="
|
||||
// Remove ANY inline event handler (on...=) in one rule instead of an
|
||||
// incomplete allow list. This also covers obfuscation by whitespace
|
||||
// before the '=' ("onerror =") and handler names that were not listed
|
||||
// before (onfocus, onbegin, onanimationstart, ...). With onfocus gone,
|
||||
// a lone "autofocus" has no handler left to trigger.
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"\\bon(click|error|focus|load|mouseover|animationstart)[\\s\\u200B	

\\r\\n\\t]*="
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"onl***="];
|
||||
result = [NSString stringWithString: newResult];
|
||||
|
||||
// Remove onmouseover
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"onmouseover="
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"onmouseo***="];
|
||||
result = [NSString stringWithString: newResult];
|
||||
|
||||
// Remove onrepeat
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"onrepeat="
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"onrep***="];
|
||||
result = [NSString stringWithString: newResult];
|
||||
|
||||
// Remove onerror
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"onerror="
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"onerr***="];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"data-blocked="];
|
||||
result = [NSString stringWithString: newResult];
|
||||
|
||||
// Remove @import css (in style tags)
|
||||
@@ -1064,12 +1058,15 @@ static int cssEscapingCount;
|
||||
|
||||
|
||||
if(stripAngular) {
|
||||
// Remove {{ and }} as they are interprated by angularJS with no way of escaping
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"(\\{\\{)|({{)"
|
||||
// Remove {{ and }} as they are interprated by angularJS with no way of escaping.
|
||||
// Cover the literal form, the hex entity ({) AND the decimal entity
|
||||
// ({), both with optional leading zeros, since the browser decodes
|
||||
// any of them back to a brace before AngularJS parses the node.
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"(\\{\\{)|(�*7b;�*7b;)|(�*123;�*123;)"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"{\\\\{"];
|
||||
result = [NSString stringWithString: newResult];
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"(\\}\\})|(}})"
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"(\\}\\})|(�*7d;�*7d;)|(�*125;�*125;)"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"}/}"];
|
||||
result = [NSString stringWithString: newResult];
|
||||
|
||||
@@ -107,11 +107,21 @@
|
||||
testEquals([[NSString stringWithString:@"<img livescript:test"] stringWithoutHTMLInjection: NO stripAngular: NO], @"<img test");
|
||||
testEquals([[NSString stringWithString:@"foobar <form action=\"\">bar</form>"] stringWithoutHTMLInjection: NO stripAngular: NO], @"foobar <for* action=\"\">bar</for*>");
|
||||
testEquals([[NSString stringWithString:@"foobar <iframe src=\"\">bar</iframe>"] stringWithoutHTMLInjection: NO stripAngular: NO], @"foobar <ifr*** src=\"\">bar</iframe>");
|
||||
testEquals([[NSString stringWithString:@"foobar <img onload=foo bar"] stringWithoutHTMLInjection: NO stripAngular: NO], @"foobar <img onl***=foo bar");
|
||||
testEquals([[NSString stringWithString:@"foobar <img onmouseover=foo bar"] stringWithoutHTMLInjection: NO stripAngular: NO], @"foobar <img onmouseo***=foo bar");
|
||||
testEquals([[NSString stringWithString:@"foobar <img onload=foo bar"] stringWithoutHTMLInjection: NO stripAngular: NO], @"foobar <img data-blocked=foo bar");
|
||||
testEquals([[NSString stringWithString:@"foobar <img onmouseover=foo bar"] stringWithoutHTMLInjection: NO stripAngular: NO], @"foobar <img data-blocked=foo bar");
|
||||
// any on...= handler is neutralised, including whitespace before '=' and names
|
||||
// that were never in the old list
|
||||
testEquals([[NSString stringWithString:@"<img src=x onerror =alert(1)>"] stringWithoutHTMLInjection: NO stripAngular: NO], @"<img src=x data-blocked=alert(1)>");
|
||||
testEquals([[NSString stringWithString:@"<input autofocus onfocus=alert(1)>"] stringWithoutHTMLInjection: NO stripAngular: NO], @"<input autofocus data-blocked=alert(1)>");
|
||||
// deletion filters loop until stable, so nesting cannot rebuild the scheme
|
||||
testEquals([[NSString stringWithString:@"javajavascript:script:"] stringWithoutHTMLInjection: NO stripAngular: NO], @"");
|
||||
testEquals([[NSString stringWithString:@"<!DOCTYPE html><html><head><style>@import url(https://foo.bar/malicious.css);.foo{background-color: red; @import url(https://bar.foo/malicious2.css);</style></head><body><table><tr><td>A</td><td>B</td><td>C</td></tr></table></body></html>"] stringWithoutHTMLInjection: NO stripAngular: NO], @"<!DOCTYPE html><html><head><style>@im**** url(https://foo.bar/malicious.css);.foo{background-color: red; @im**** url(https://bar.foo/malicious2.css);</style></head><body><table><tr><td>A</td><td>B</td><td>C</td></tr></table></body></html>");
|
||||
// the @import cleanup must still run when angular interpolation is stripped as well
|
||||
testEquals([[NSString stringWithString:@"<style>@import url(https://foo.bar/malicious.css);</style>"] stringWithoutHTMLInjection: NO stripAngular: YES], @"<style>@im**** url(https://foo.bar/malicious.css);</style>");
|
||||
// literal braces are rewritten so AngularJS cannot interpolate them
|
||||
testEquals([[NSString stringWithString:@"{{1337*1337}}"] stringWithoutHTMLInjection: NO stripAngular: YES], @"{\\{1337*1337}/}");
|
||||
// ... and so are the decimal HTML entities the browser would decode back to braces
|
||||
testEquals([[NSString stringWithString:@"{{1337*1337}}"] stringWithoutHTMLInjection: NO stripAngular: YES], @"{\\{1337*1337}/}");
|
||||
}
|
||||
|
||||
- (void) test_stringCleanInvalidHTMLTags
|
||||
|
||||
Reference in New Issue
Block a user