mirror of
https://github.com/smarty-php/smarty.git
synced 2025-08-03 18:04:26 +02:00
Applied appropriate javascript and html escaping in mailto plugin to counter injection attacks
Fixes #454
This commit is contained in:
@@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- Applied appropriate javascript and html escaping in mailto plugin to counter injection attacks [#454](https://github.com/smarty-php/smarty/issues/454)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fixed PHP8.1 deprecation errors in modifiers (upper, explode, number_format and replace) [#755](https://github.com/smarty-php/smarty/pull/755) and [#788](https://github.com/smarty-php/smarty/pull/788)
|
- Fixed PHP8.1 deprecation errors in modifiers (upper, explode, number_format and replace) [#755](https://github.com/smarty-php/smarty/pull/755) and [#788](https://github.com/smarty-php/smarty/pull/788)
|
||||||
- Fixed PHP8.1 deprecation errors in capitalize modifier [#789](https://github.com/smarty-php/smarty/issues/789)
|
- Fixed PHP8.1 deprecation errors in capitalize modifier [#789](https://github.com/smarty-php/smarty/issues/789)
|
||||||
|
@@ -48,8 +48,13 @@
|
|||||||
*/
|
*/
|
||||||
function smarty_function_mailto($params)
|
function smarty_function_mailto($params)
|
||||||
{
|
{
|
||||||
static $_allowed_encoding =
|
static $_allowed_encoding = [
|
||||||
array('javascript' => true, 'javascript_charcode' => true, 'hex' => true, 'none' => true);
|
'javascript' => true,
|
||||||
|
'javascript_charcode' => true,
|
||||||
|
'hex' => true,
|
||||||
|
'none' => true
|
||||||
|
];
|
||||||
|
|
||||||
$extra = '';
|
$extra = '';
|
||||||
if (empty($params[ 'address' ])) {
|
if (empty($params[ 'address' ])) {
|
||||||
trigger_error("mailto: missing 'address' parameter", E_USER_WARNING);
|
trigger_error("mailto: missing 'address' parameter", E_USER_WARNING);
|
||||||
@@ -57,19 +62,19 @@ function smarty_function_mailto($params)
|
|||||||
} else {
|
} else {
|
||||||
$address = $params[ 'address' ];
|
$address = $params[ 'address' ];
|
||||||
}
|
}
|
||||||
|
|
||||||
$text = $address;
|
$text = $address;
|
||||||
|
|
||||||
// netscape and mozilla do not decode %40 (@) in BCC field (bug?)
|
// netscape and mozilla do not decode %40 (@) in BCC field (bug?)
|
||||||
// so, don't encode it.
|
// so, don't encode it.
|
||||||
$search = array('%40', '%2C');
|
$mail_parms = [];
|
||||||
$replace = array('@', ',');
|
|
||||||
$mail_parms = array();
|
|
||||||
foreach ($params as $var => $value) {
|
foreach ($params as $var => $value) {
|
||||||
switch ($var) {
|
switch ($var) {
|
||||||
case 'cc':
|
case 'cc':
|
||||||
case 'bcc':
|
case 'bcc':
|
||||||
case 'followupto':
|
case 'followupto':
|
||||||
if (!empty($value)) {
|
if (!empty($value)) {
|
||||||
$mail_parms[] = $var . '=' . str_replace($search, $replace, rawurlencode($value));
|
$mail_parms[] = $var . '=' . str_replace(['%40', '%2C'], ['@', ','], rawurlencode($value));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'subject':
|
case 'subject':
|
||||||
@@ -83,6 +88,7 @@ function smarty_function_mailto($params)
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($mail_parms) {
|
if ($mail_parms) {
|
||||||
$address .= '?' . join('&', $mail_parms);
|
$address .= '?' . join('&', $mail_parms);
|
||||||
}
|
}
|
||||||
@@ -94,19 +100,21 @@ function smarty_function_mailto($params)
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$string = '<a href="mailto:' . htmlspecialchars($address, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, Smarty::$_CHARSET) .
|
||||||
|
'" ' . $extra . '>' . htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, Smarty::$_CHARSET) . '</a>';
|
||||||
|
|
||||||
if ($encode === 'javascript') {
|
if ($encode === 'javascript') {
|
||||||
$string = '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>';
|
|
||||||
$js_encode = '';
|
$js_encode = '';
|
||||||
for ($x = 0, $_length = strlen($string); $x < $_length; $x++) {
|
for ($x = 0, $_length = strlen($string); $x < $_length; $x++) {
|
||||||
$js_encode .= '%' . bin2hex($string[ $x ]);
|
$js_encode .= '%' . bin2hex($string[ $x ]);
|
||||||
}
|
}
|
||||||
return '<script type="text/javascript">document.write(unescape(\'' . $js_encode . '\'))</script>';
|
return '<script type="text/javascript">document.write(unescape(\'' . $js_encode . '\'))</script>';
|
||||||
} elseif ($encode === 'javascript_charcode') {
|
} elseif ($encode === 'javascript_charcode') {
|
||||||
$string = '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>';
|
|
||||||
for ($x = 0, $_length = strlen($string); $x < $_length; $x++) {
|
for ($x = 0, $_length = strlen($string); $x < $_length; $x++) {
|
||||||
$ord[] = ord($string[ $x ]);
|
$ord[] = ord($string[ $x ]);
|
||||||
}
|
}
|
||||||
return '<script type="text/javascript">document.write(String.fromCharCode(' . implode(',', $ord) . '))</script>';
|
return '<script type="text/javascript">document.write(String.fromCharCode(' . implode(',', $ord) . '))</script>';
|
||||||
} elseif ($encode === 'hex') {
|
} elseif ($encode === 'hex') {
|
||||||
preg_match('!^(.*)(\?.*)$!', $address, $match);
|
preg_match('!^(.*)(\?.*)$!', $address, $match);
|
||||||
if (!empty($match[ 2 ])) {
|
if (!empty($match[ 2 ])) {
|
||||||
@@ -129,6 +137,6 @@ function smarty_function_mailto($params)
|
|||||||
return '<a href="' . $mailto . $address_encode . '" ' . $extra . '>' . $text_encode . '</a>';
|
return '<a href="' . $mailto . $address_encode . '" ' . $extra . '>' . $text_encode . '</a>';
|
||||||
} else {
|
} else {
|
||||||
// no encoding
|
// no encoding
|
||||||
return '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>';
|
return $string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -150,7 +150,7 @@ class PluginFunctionMailtoTest extends PHPUnit_Smarty
|
|||||||
|
|
||||||
public function testUmlauts()
|
public function testUmlauts()
|
||||||
{
|
{
|
||||||
$result = '<a href="mailto:me+smtpext@example.com?cc=you@example.com,they@example.com&subject=h%C3%A4llo%20w%C3%B6rld" >me+smtpext@example.com</a>';
|
$result = '<a href="mailto:me+smtpext@example.com?cc=you@example.com,they@example.com&subject=h%C3%A4llo%20w%C3%B6rld" >me+smtpext@example.com</a>';
|
||||||
$tpl = $this->smarty->createTemplate('eval:{mailto address="me+smtpext@example.com" cc="you@example.com,they@example.com" subject="hällo wörld"}');
|
$tpl = $this->smarty->createTemplate('eval:{mailto address="me+smtpext@example.com" cc="you@example.com,they@example.com" subject="hällo wörld"}');
|
||||||
$this->assertEquals(str_replace("\r", '', $result), $this->smarty->fetch($tpl));
|
$this->assertEquals(str_replace("\r", '', $result), $this->smarty->fetch($tpl));
|
||||||
}
|
}
|
||||||
@@ -158,9 +158,26 @@ class PluginFunctionMailtoTest extends PHPUnit_Smarty
|
|||||||
public function testUmlautsWithoutMbstring()
|
public function testUmlautsWithoutMbstring()
|
||||||
{
|
{
|
||||||
Smarty::$_MBSTRING = false;
|
Smarty::$_MBSTRING = false;
|
||||||
$result = '<a href="mailto:me+smtpext@example.com?cc=you@example.com,they@example.com&subject=h%C3%A4llo%20w%C3%B6rld" >me+smtpext@example.com</a>';
|
$result = '<a href="mailto:me+smtpext@example.com?cc=you@example.com,they@example.com&subject=h%C3%A4llo%20w%C3%B6rld" >me+smtpext@example.com</a>';
|
||||||
$tpl = $this->smarty->createTemplate('eval:{mailto address="me+smtpext@example.com" cc="you@example.com,they@example.com" subject="hällo wörld"}');
|
$tpl = $this->smarty->createTemplate('eval:{mailto address="me+smtpext@example.com" cc="you@example.com,they@example.com" subject="hällo wörld"}');
|
||||||
$this->assertEquals(str_replace("\r", '', $result), $this->smarty->fetch($tpl));
|
$this->assertEquals(str_replace("\r", '', $result), $this->smarty->fetch($tpl));
|
||||||
Smarty::$_MBSTRING = true;
|
Smarty::$_MBSTRING = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testJavascriptChars()
|
||||||
|
{
|
||||||
|
$result = '<script type="text/javascript">document.write(unescape(\'%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%26%71%75%6f%74%3b%26%67%74%3b%6d%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%26%23%30%33%39%3b%29%3b%20%61%6c%65%72%74%28%26%71%75%6f%74%3b%69%6e%6a%65%63%74%69%6f%6e%26%71%75%6f%74%3b%29%3b%20%2f%2f%22%20%3e%6d%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%26%71%75%6f%74%3b%26%67%74%3b%6d%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%26%23%30%33%39%3b%29%3b%20%61%6c%65%72%74%28%26%71%75%6f%74%3b%69%6e%6a%65%63%74%69%6f%6e%26%71%75%6f%74%3b%29%3b%20%2f%2f%3c%2f%61%3e\'))</script>';
|
||||||
|
$this->smarty->assign('address', 'me@example.com">me@example.com\'); alert("injection"); //');
|
||||||
|
$tpl = $this->smarty->createTemplate('eval:{mailto address=$address encode=javascript}');
|
||||||
|
$this->assertEquals(str_replace("\r", '', $result), $this->smarty->fetch($tpl));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHtmlChars()
|
||||||
|
{
|
||||||
|
$result = '<a href="mailto:me@example.com"><h1>" class="email">me@example.com"><h1></a>';
|
||||||
|
$this->smarty->assign('address', 'me@example.com"><h1>');
|
||||||
|
$tpl = $this->smarty->createTemplate('eval:{mailto address=$address extra=\'class="email"\'}');
|
||||||
|
$this->assertEquals(str_replace("\r", '', $result), $this->smarty->fetch($tpl));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user