Skip to content

Commit

Permalink
fix(security): Security fix for WSTG-INPV-02. Add XSS protection on f…
Browse files Browse the repository at this point in the history
…olders and mail title / content
  • Loading branch information
WoodySlum committed Nov 14, 2022
1 parent 9674793 commit 714acfc
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 8 deletions.
2 changes: 1 addition & 1 deletion SoObjects/Mailer/SOGoDraftObject.m
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ - (NSDictionary *) headers

- (void) setText: (NSString *) newText
{
ASSIGN (text, newText);
ASSIGN (text, [newText stringWithoutHTMLInjection: NO]);
}

- (NSString *) text
Expand Down
2 changes: 2 additions & 0 deletions SoObjects/SOGo/NSString+Utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@
/* OpenSSL multiline DN */
- (NSArray *) componentsFromMultilineDN;

- (NSString *) stringWithoutHTMLInjection: (BOOL)stripHTMLCode;

#ifndef GNUSTEP_BASE_LIBRARY
- (BOOL) boolValue;
#endif
Expand Down
81 changes: 81 additions & 0 deletions SoObjects/SOGo/NSString+Utilities.m
Original file line number Diff line number Diff line change
Expand Up @@ -891,4 +891,85 @@ - (NSString *) decryptWithKey: (NSString *) theKey
return result;
}

/**
* Get the safe string avoiding HTML injection
* @param stripHTMLCode Remove all HTML code from content
* @return A safe string
*/
- (NSString *) stringWithoutHTMLInjection: (BOOL)stripHTMLCode
{
NSString *result, *text;
NSScanner *theScanner;
NSError *error;
NSRegularExpression *regex;

text = nil;
error = nil;
regex = nil;
result = [NSString stringWithString: self];

if (stripHTMLCode) {
// Author : https://www.codercrunch.com/question/1251681838/how-remove-html-tags-string-ios
theScanner = [NSScanner scannerWithString: result];
while ([theScanner isAtEnd] == NO) {
// find start of tag
[theScanner scanUpToString: @"<" intoString: NULL];
// find end of tag
[theScanner scanUpToString: @">" intoString: &text];
// replace the found tag with a space
//(you can filter multi-spaces out later if you wish)
result = [result stringByReplacingOccurrencesOfString:
[NSString stringWithFormat: @"%@>", text]
withString: @" "];
}
} else {
// Clean XSS
// Examples of injection : https://cheatsheetseries.owasp.org/cheatsheets/XSS_Filter_Evasion_Cheat_Sheet.html#xss-locator-polygot
result = [self stringByReplacingOccurrencesOfString:@"<script" withString:@""];
result = [result stringByReplacingOccurrencesOfString:@"</script>" withString:@""];

// Remove javascript:
regex = [NSRegularExpression regularExpressionWithPattern:@"j[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*a[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*v[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*a[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*s[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*c[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*r[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*i[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*p[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*t[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*:"
options: NSRegularExpressionCaseInsensitive error:&error];
result = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];

// Remove vbscript:
regex = [NSRegularExpression regularExpressionWithPattern:@"v[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*b[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*s[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*r[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*i[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*p[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*t[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*:"
options: NSRegularExpressionCaseInsensitive error:&error];
result = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];

// Remove livescript:
regex = [NSRegularExpression regularExpressionWithPattern:@"l[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*i[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*v[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*e[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*s[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*c[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*r[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*i[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*p[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*t[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*:"
options: NSRegularExpressionCaseInsensitive error:&error];
result = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];

// Remove <script
regex = [NSRegularExpression regularExpressionWithPattern:@"<[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*s[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*c[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*r[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*i[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*p[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*t"
options: NSRegularExpressionCaseInsensitive error:&error];
result = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"<scr***"];

// Remove </script
regex = [NSRegularExpression regularExpressionWithPattern:@"<[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*/[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*s[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*c[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*r[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*i[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*p[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*t"
options: NSRegularExpressionCaseInsensitive error:&error];
result = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"</scr***"];

// Remove <iframe
regex = [NSRegularExpression regularExpressionWithPattern:@"<[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*i[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*f[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*r[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*a[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*m[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*e"
options: NSRegularExpressionCaseInsensitive error:&error];
result = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"<ifr***"];

// Remove onload
regex = [NSRegularExpression regularExpressionWithPattern:@"onload="
options: NSRegularExpressionCaseInsensitive error:&error];
result = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"onl***="];

// Remove onmouseover
regex = [NSRegularExpression regularExpressionWithPattern:@"onmouseover="
options: NSRegularExpressionCaseInsensitive error:&error];
result = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"onmouseo***="];
}

return result;
}

@end
2 changes: 1 addition & 1 deletion UI/Common/UIxParentFolderActions.m
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ @implementation UIxParentFolderActions
request = [context request];
params = [[request contentAsString] objectFromJSONString];

name = [params objectForKey: @"name"];
name = [[params objectForKey: @"name"] stringWithoutHTMLInjection: YES];
nameInContainer = nil;

if ([name length] > 0)
Expand Down
2 changes: 1 addition & 1 deletion UI/MailPartViewers/UIxMailPartViewer.m
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ - (id) renderedPart
return [NSDictionary dictionaryWithObjectsAndKeys:
[self className], @"type",
type, @"contentType",
[[self generateResponse] contentAsString], @"content",
[[[self generateResponse] contentAsString] stringWithoutHTMLInjection: NO], @"content",
[self filenameForDisplay], @"filename",
[self preferredPathExtension], @"extension",
[[self sizeFormatter] stringForObjectValue: [bodyInfo objectForKey: @"size"]], @"size",
Expand Down
4 changes: 2 additions & 2 deletions UI/MailerUI/UIxMailFolderActions.m
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ @implementation UIxMailFolderActions

request = [context request];
params = [[request contentAsString] objectFromJSONString];
folderName = [params objectForKey: @"name"];
folderName = [[params objectForKey: @"name"] stringWithoutHTMLInjection: YES];
if ([folderName length] > 0)
{
encodedFolderName = [folderName stringByEncodingImap4FolderName];
Expand Down Expand Up @@ -142,7 +142,7 @@ - (WOResponse *) renameFolderAction
// Retrieve new folder name from JSON payload
request = [context request];
params = [[request contentAsString] objectFromJSONString];
newFolderName = [params objectForKey: @"name"];
newFolderName = [[params objectForKey: @"name"] stringWithoutHTMLInjection: YES];

if (!newFolderName || [newFolderName length] == 0)
{
Expand Down
2 changes: 1 addition & 1 deletion UI/MailerUI/UIxMailListActions.m
Original file line number Diff line number Diff line change
Expand Up @@ -976,7 +976,7 @@ - (NSArray *) getHeadersForUIDs: (NSArray *) uids
[msg addObject: [NSNumber numberWithBool: [self isMessageFlagged]]];

// Subject
[msg addObject: [self messageSubject]];
[msg addObject: [[self messageSubject] stringWithoutHTMLInjection: YES]];

// From
from = [[message objectForKey: @"envelope"] from];
Expand Down
2 changes: 1 addition & 1 deletion UI/MailerUI/UIxMailView.m
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ those are the IMAP4 flags (and annotations, which we do not use).
if ([self formattedDate])
[data setObject: [self formattedDate] forKey: @"date"];
if ([self messageSubject])
[data setObject: [self messageSubject] forKey: @"subject"];
[data setObject: [[self messageSubject] stringWithoutHTMLInjection: YES] forKey: @"subject"];
if ((addresses = [addressFormatter dictionariesForArray: [co fromEnvelopeAddresses]]))
[data setObject: addresses forKey: @"from"];
if ((addresses = [addressFormatter dictionariesForArray: [co toEnvelopeAddresses]]))
Expand Down
2 changes: 1 addition & 1 deletion UI/Scheduler/UIxCalendarSelector.m
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ - (NSArray *) calendars
fActiveTasks = [folder activeTasks];

[calendar setObject: folderName forKey: @"id"];
[calendar setObject: fDisplayName forKey: @"name"];
[calendar setObject: [fDisplayName stringWithoutHTMLInjection: YES] forKey: @"name"];
[calendar setObject: [folder calendarColor] forKey: @"color"];
isActive = [NSNumber numberWithBool: [folder isActive]];
[calendar setObject: isActive forKey: @"active"];
Expand Down

0 comments on commit 714acfc

Please sign in to comment.