[SECURITY] t3lib_div::quoteJSvalue allows XSS
[Packages/TYPO3.CMS.git] / t3lib / codec / class.t3lib_codec_javascriptencoder.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2012 Franz G. Jahn <franzjahn@cron-it.de>
6 * (c) 2012 Helmut Hummel <helmut.hummel@typo3.org>
7 * All rights reserved
8 *
9 * This script is part of the TYPO3 project. The TYPO3 project is
10 * free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * The GNU General Public License can be found at
16 * http://www.gnu.org/copyleft/gpl.html.
17 *
18 * This script is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * This copyright notice MUST APPEAR in all copies of the script!
24 ***************************************************************/
25
26 /**
27 * Adopted from OWASP Enterprise Security API (ESAPI) reference implementation for the JavaScript Codec.
28 * Original Author: Mike Boberski
29 *
30 * This class provides encoding for user input that is intended to be used in a JavaScript context.
31 * It encodes all characters except alphanumericals and the immune characters to a hex representation.
32 *
33 * @package TYPO3
34 * @subpackage t3lib
35 *
36 * @author Mike Boberski <boberski_michael@bah.com>
37 * @copyright 2009-2010 The OWASP Foundation
38 * @link http://www.owasp.org/index.php/ESAPI
39 *
40 * @author Franz G. Jahn <franzjahn@cron-it.de>
41 * @author Helmut Hummel <helmut.hummel@typo3.org>
42 */
43 class t3lib_codec_JavaScriptEncoder implements t3lib_Singleton {
44 /**
45 * A map where the keys are ordinal values of non-alphanumeric single-byte
46 * characters and the values are hexadecimal equivalents as strings.
47 *
48 * @var array
49 */
50 protected $hexMatrix = array();
51
52 /**
53 * Characters that are immune (not dangerous) in the JavaScript context
54 *
55 * @var array
56 */
57 protected $immuneCharacters = array(',', '.', '_' );
58
59 /**
60 * TYPO3 charset encoding object
61 *
62 * @var t3lib_cs
63 */
64 protected $charsetConversion = NULL;
65
66 /**
67 * Populates the $hex map of non-alphanumeric single-byte characters.
68 *
69 * Alphanumerical character are set to NULL in the matrix.
70 */
71 public function __construct() {
72 $this->charsetConversion = t3lib_div::makeInstance('t3lib_cs');
73
74 for ($i = 0; $i < 256; $i++) {
75 if (($i >= ord('0') && $i <= ord('9')) || ($i >= ord('A') && $i <= ord('Z')) || ($i >= ord('a') && $i <= ord('z'))) {
76 $this->hexMatrix[$i] = NULL;
77 } else {
78 $this->hexMatrix[$i] = dechex($i);
79 }
80 }
81 }
82
83 /**
84 * Encodes a string for JavaScript.
85 *
86 * @param string $input The string to encode, may be empty.
87 * @return string The encoded string.
88 */
89 public function encode($input) {
90 $stringLength = $this->charsetConversion->strlen('utf-8', $input);
91 $encodedString = '';
92 for ($i = 0; $i < $stringLength; $i++) {
93 $c = $this->charsetConversion->substr('utf-8', $input, $i, 1);
94 $encodedString .= $this->encodeCharacter($c);
95 }
96
97 return $encodedString;
98 }
99
100 /**
101 * Returns backslash encoded numeric format. Does not use backslash
102 * character escapes such as, \" or \' as these may cause parsing problems.
103 * For example, if a javascript attribute, such as onmouseover, contains
104 * a \" that will close the entire attribute and allow an attacker to inject
105 * another script attribute.
106 *
107 * @param string $character utf-8 character that needs to be encoded
108 * @return string encoded character
109 */
110 protected function encodeCharacter($character) {
111 if ($this->isImmuneCharacter($character)) {
112 return $character;
113 }
114
115 $ordinalValue = $this->charsetConversion->utf8CharToUnumber($character);
116
117 // Check for alphanumeric characters
118 $hex = $this->getHexForNonAlphanumeric($ordinalValue);
119 if ($hex === NULL) {
120 return $character;
121 }
122
123 // Encode up to 256 with \\xHH
124 if ($ordinalValue < 256) {
125 $pad = substr('00', strlen($hex));
126 return '\\x' . $pad . strtoupper($hex);
127 }
128
129 // Otherwise encode with \\uHHHH
130 $pad = substr('0000', strlen($hex));
131 return '\\u' . $pad . strtoupper($hex);
132 }
133
134 /**
135 * Checks if the given character is one of the immune characters
136 *
137 * @param string $character utf-8 character to search for, must not be empty
138 * @return boolean TRUE if character is immune, FALSE otherwise
139 */
140 protected function isImmuneCharacter($character) {
141 return in_array($character, $this->immuneCharacters, TRUE);
142 }
143
144 /**
145 * Returns the ordinal value as a hex string of any character that is not a
146 * single-byte alphanumeric. The character should be supplied as a string in
147 * the utf-8 character encoding.
148 * If the character is an alphanumeric character with ordinal value below 255,
149 * then this method will return NULL.
150 *
151 * @param integer $ordinalValue Ordinal value of the character
152 * @return string hexadecimal ordinal value of non-alphanumeric characters or NULL otherwise.
153 */
154 protected function getHexForNonAlphanumeric($ordinalValue) {
155 if ($ordinalValue <= 255) {
156 return $this->hexMatrix[$ordinalValue];
157 }
158 return dechex($ordinalValue);
159 }
160 }
161 ?>