|
1
|
ISSUE DESCRIPTION:
|
|
2
|
*[MAJOR]* _security_ @WebPageHandler@.@WebPageKeysProvider@: Admin-configured connection messages are inserted into single-quoted JS string literals in index.html (e.g. @'tryToConnectMessage' : '${tryToConnectMessage}'@) with no JS-string escaping (WebPageHandler.java:237-246, index.html:122-124). A value containing @'@, @\@, @\n@, or @</script>@ breaks out of the literal and yields arbitrary JS execution in every web client. @Utils.removeEscapedDoubleQuotes@ only strips a leading/trailing @\"...\"@ artifact and provides no XSS protection. Apply a proper JS-string encoder (or JSON-encode the value before interpolation).
|
|
3
|
|
|
4
|
PROPOSED FIX:
|
|
5
|
Introduce a dedicated `escapeJsString(String)` helper in `Utils` that escapes the characters that can break out of a single-quoted JS literal embedded in an HTML <script> block: backslash, single/double quote, CR/LF, U+2028, U+2029, and the `</` sequence (to prevent premature </script> termination). Apply it in `WebPageHandler.WebPageKeysProvider` around every admin-supplied connection message before the value is interpolated into index.html. The legacy `removeEscapedDoubleQuotes` only strips a wrapper artifact and is orthogonal to escaping, so keep stripping the wrapper first and then escape the remainder.
|
|
6
|
|
|
7
|
CHANGES:
|
|
8
|
/home/sbi/projects/10915a/src/com/goldencode/p2j/util/Utils.java
|
|
9
|
```java
|
|
10
|
public static String removeEscapedDoubleQuotes(String text)
|
|
11
|
{
|
|
12
|
if (text == null)
|
|
13
|
{
|
|
14
|
return text;
|
|
15
|
}
|
|
16
|
|
|
17
|
int end = text.length();
|
|
18
|
|
|
19
|
if (text.startsWith("\\\"") && end > 3 && text.endsWith("\\\""))
|
|
20
|
{
|
|
21
|
return text.substring(2, end - 2);
|
|
22
|
}
|
|
23
|
|
|
24
|
return text;
|
|
25
|
}
|
|
26
|
|
|
27
|
/**
|
|
28
|
* Escape a string so that it can be safely embedded inside a single- or
|
|
29
|
* double-quoted JavaScript string literal that itself appears inside an
|
|
30
|
* HTML <script> block. Escapes backslash, both quote styles, CR/LF,
|
|
31
|
* line/paragraph separators (U+2028/U+2029) and the "</"
|
|
32
|
* sequence to prevent premature </script> termination.
|
|
33
|
*
|
|
34
|
* @param text
|
|
35
|
* The string to escape, or {@code null}.
|
|
36
|
*
|
|
37
|
* @return A JS-safe representation of {@code text}, or an empty string
|
|
38
|
* if {@code text} is {@code null}.
|
|
39
|
*/
|
|
40
|
public static String escapeJsString(String text)
|
|
41
|
{
|
|
42
|
if (text == null)
|
|
43
|
{
|
|
44
|
return "";
|
|
45
|
}
|
|
46
|
StringBuilder sb = new StringBuilder(text.length() + 16);
|
|
47
|
for (int i = 0, n = text.length(); i < n; i++)
|
|
48
|
{
|
|
49
|
char c = text.charAt(i);
|
|
50
|
switch (c)
|
|
51
|
{
|
|
52
|
case '\\': sb.append("\\\\"); break;
|
|
53
|
case '\'': sb.append("\\'"); break;
|
|
54
|
case '"': sb.append("\\\""); break;
|
|
55
|
case '\n': sb.append("\\n"); break;
|
|
56
|
case '\r': sb.append("\\r"); break;
|
|
57
|
case '\t': sb.append("\\t"); break;
|
|
58
|
case '\b': sb.append("\\b"); break;
|
|
59
|
case '\f': sb.append("\\f"); break;
|
|
60
|
case '
': sb.append("\\u2028"); break;
|
|
61
|
case '
': sb.append("\\u2029"); break;
|
|
62
|
case '<':
|
|
63
|
// break "</" so a stray "</script>" cannot terminate the block
|
|
64
|
if (i + 1 < n && text.charAt(i + 1) == '/')
|
|
65
|
{
|
|
66
|
sb.append("\\u003c");
|
|
67
|
}
|
|
68
|
else
|
|
69
|
{
|
|
70
|
sb.append(c);
|
|
71
|
}
|
|
72
|
break;
|
|
73
|
default:
|
|
74
|
sb.append(c);
|
|
75
|
}
|
|
76
|
}
|
|
77
|
return sb.toString();
|
|
78
|
}
|
|
79
|
```
|
|
80
|
|
|
81
|
/home/sbi/projects/10915a/src/com/goldencode/p2j/ui/client/driver/web/WebPageHandler.java
|
|
82
|
```java
|
|
83
|
add(ConfigItem.TRY_CONNECT_MSG.name(), () -> Utils.escapeJsString(
|
|
84
|
Utils.removeEscapedDoubleQuotes(config.getString(
|
|
85
|
ConfigItem.TRY_CONNECT_MSG, WebConfigurationConstants.TRY_TO_CONNECT_MESSAGE))));
|
|
86
|
|
|
87
|
add(ConfigItem.CONNECTION_RESTORED_MSG.name(),
|
|
88
|
() -> Utils.escapeJsString(Utils.removeEscapedDoubleQuotes(config.getString(
|
|
89
|
ConfigItem.CONNECTION_RESTORED_MSG,
|
|
90
|
WebConfigurationConstants.CONNECTION_RESTORED_MESSAGE))));
|
|
91
|
|
|
92
|
add(ConfigItem.SERVER_UNAVAILABLE_MSG.name(),
|
|
93
|
() -> Utils.escapeJsString(Utils.removeEscapedDoubleQuotes(config.getString(
|
|
94
|
ConfigItem.SERVER_UNAVAILABLE_MSG,
|
|
95
|
WebConfigurationConstants.SERVER_UNAVAILABLE_MESSAGE))));
|
|
96
|
```
|