Sanitize messages at server side

This commit is contained in:
Dmitriy Simushev 2014-09-12 10:59:56 +00:00
parent ce6761755e
commit ae9de7aa92
9 changed files with 31 additions and 103 deletions

View File

@ -17,24 +17,6 @@
*/
(function(Mibew, Handlebars){
/**
* Register 'allowTags' Handlebars helper.
*
* This helper unescape HTML entities for allowed (span and strong) tags.
*/
Handlebars.registerHelper('allowTags', function(text) {
var result = text.toString();
result = result.replace(
/<(span|strong)>(.*?)<\/\1>/g,
'<$1>$2</$1>'
);
result = result.replace(
/&lt;span class=&quot;(.*?)&quot;&gt;(.*?)&lt;\/span&gt;/g,
'<span class="$1">$2</span>'
);
return new Handlebars.SafeString(result);
});
/**
* Register 'formatTime' Handlebars helper.
*

View File

@ -18,27 +18,6 @@
(function(Mibew, Backbone, Handlebars) {
/**
* List of replacements pairs
* @type Object
* @private
*/
var badCharList = {
"<": "&lt;",
">": "&gt;",
"&": "&amp;",
'"': "&quot;",
"'": "&#x27;",
"`": "&#x60;"
}
/**
* Regular expression for characters that must be replaced by HTML entities
* @type RegExp
* @private
*/
var badCharRegEx = /[&<>'"`]/g;
/**
* @class Represents default message view
*/
@ -75,10 +54,7 @@
var messageKind = this.model.get('kind');
// Add message fields
msg.allowFormatting = (messageKind != this.model.KIND_USER
&& messageKind != this.model.KIND_AGENT);
msg.kindName = this.kindToString(messageKind);
msg.message = this.escapeString(msg.message);
return msg;
},
@ -111,22 +87,6 @@
return "plugin";
}
return "";
},
/**
* Replace HTML special characters('<', '>', '&', "'", '"', '`') by
* corresponding HTML entities.
*
* @param {String} str Unescaped string
* @returns {String} Escaped string
*/
escapeString: function(str) {
return str.replace(
badCharRegEx,
function(chr) {
return badCharList[chr] || "&amp;";
}
);
}
}
);

View File

@ -50,6 +50,26 @@ function message_to_text($msg)
}
}
/**
* Sanitize message body and make it a safe HTML string.
*
* @param array $msg Message object
* @return array Message object with sanitized body.
*/
function sanitize_message($msg)
{
$message_body = $msg['message'];
// Messages entered by user or operator cannot contain any markup
if ($msg['kind'] == Thread::KIND_USER || $msg['kind'] == Thread::KIND_AGENT) {
$message_body = safe_htmlspecialchars($message_body);
}
$msg['message'] = sanitize_string($message_body, 'low', 'moderate');
return $msg;
}
/**
* Format username
*

View File

@ -197,7 +197,10 @@ class HistoryController extends AbstractController
// Build messages list
$last_id = -1;
$messages = $thread->getMessages(false, $last_id);
$messages = array_map(
'sanitize_message',
$thread->getMessages(false, $last_id)
);
$page['threadMessages'] = json_encode($messages);
$page['title'] = getlocal("Chat log");

View File

@ -340,10 +340,10 @@ class ThreadProcessor extends ClientSideProcessor implements RouterAwareInterfac
// Send new messages
$last_message_id = $args['lastId'];
$messages = $thread->getMessages($args['user'], $last_message_id);
if (empty($messages)) {
$messages = array();
}
$messages = array_map(
'sanitize_message',
$thread->getMessages($args['user'], $last_message_id)
);
return array(
'messages' => $messages,

View File

@ -1,3 +1,3 @@
<span>{{formatTime created}}</span>
{{#if name}}<span class='n{{kindName}}'>{{name}}</span>: {{/if}}
<span class='m{{kindName}}'>{{#if allowFormatting}}{{allowTags (nl2br (urlReplace message))}}{{else}}{{nl2br (urlReplace message)}}{{/if}}</span><br/>
<span class='m{{kindName}}'>{{nl2br (urlReplace message)}}</span><br/>

View File

@ -1,3 +1,3 @@
<span>{{formatTime created}}</span>
{{#if name}}<span class='n{{kindName}}'>{{name}}</span>: {{/if}}
<span class='m{{kindName}}'>{{#if allowFormatting}}{{allowTags (nl2br (urlReplace message))}}{{else}}{{nl2br (urlReplace message)}}{{/if}}</span><br/>
<span class='m{{kindName}}'>{{nl2br (urlReplace message)}}</span><br/>

View File

@ -1,3 +1,3 @@
<span>{{formatTime created}}</span>
{{#if name}}<span class='n{{kindName}}'>{{name}}</span>: {{/if}}
<span class='m{{kindName}}'>{{#if allowFormatting}}{{allowTags (nl2br (urlReplace message))}}{{else}}{{nl2br (urlReplace message)}}{{/if}}</span><br/>
<span class='m{{kindName}}'>{{nl2br (urlReplace message)}}</span><br/>

View File

@ -37,43 +37,6 @@ test('urlReplace', function() {
);
});
// Test "allowTags" Handlebars helper
test('allowTags', function() {
var template = '{{allowTags foo}}';
var compiledTemplate = Handlebars.compile(template);
var escape = Handlebars.Utils.escapeExpression;
equal(
compiledTemplate({foo: escape('<span>The content</span>')}),
'<span>The content</span>',
'Test a tag without attributes'
);
equal(
compiledTemplate({foo: escape('<span class="red">The content</span>')}),
'<span class="red">The content</span>',
'Test a tag with class attribute'
);
equal(
compiledTemplate({foo: escape('<span data-foo="bar">The content</span>')}),
escape('<span data-foo="bar">The content</span>'),
'Test a tag with arbitrary attributes'
);
equal(
compiledTemplate({foo: 'content'}),
'content',
'Test not a tag'
);
equal(
compiledTemplate({foo: 456}),
'456',
'Test not a string argument'
);
});
// Test "nl2br" Handlebars helper
test('nl2br', function() {
var template = '{{nl2br foo}}';