Skip to content

Commit b7cbc53

Browse files
committed
Close ESAPI#306. Close ESAPI#359
1 parent 6438ad0 commit b7cbc53

File tree

2 files changed

+149
-1
lines changed

2 files changed

+149
-1
lines changed

src/main/java/org/owasp/esapi/codecs/PercentCodec.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,12 @@ private static StringBuilder appendTwoUpperHex(StringBuilder sb, int b)
8989

9090
/**
9191
* Encode a character for URLs
92-
* @param immune characters not to encode
92+
* @param immune Additional characters not to encode. Note this could
93+
* break URL encoding as referenced in RFC 3986. You should
94+
* especially be wary of including '%' in this list of immune
95+
* characters since it is used as the "escape" character for
96+
* the hex encoding and including it may result in subsequent
97+
* and/or dangerous results when decoding.
9398
* @param c character to encode
9499
* @return the encoded string representing c
95100
*/
@@ -99,6 +104,11 @@ public String encodeCharacter( char[] immune, Character c )
99104
byte[] bytes;
100105
StringBuilder sb;
101106

107+
// check for user specified immune characters
108+
if ( immune != null && containsCharacter( c.charValue(), immune ) )
109+
return cStr;
110+
111+
// check for standard characters (e.g., alphanumeric, etc.)
102112
if(UNENCODED_SET.contains(c))
103113
return cStr;
104114

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package org.owasp.esapi.codecs;
2+
3+
import java.util.ArrayList;
4+
import java.util.Arrays;
5+
import java.util.Collection;
6+
import java.util.List;
7+
8+
import org.junit.Assert;
9+
import org.junit.Test;
10+
import org.junit.runner.RunWith;
11+
import org.junit.runners.Parameterized;
12+
import org.junit.runners.Parameterized.Parameters;
13+
import org.owasp.esapi.EncoderConstants;
14+
import org.owasp.esapi.StringUtilities;
15+
import org.owasp.esapi.codecs.*;
16+
17+
/**
18+
* Parameterized test to verify that the Immunity parameter for a codec
19+
* encode/decode event works as expected on a series of special characters.
20+
*
21+
22+
* @since 2.1.0.1
23+
*
24+
*/
25+
@RunWith(Parameterized.class)
26+
public class CodecImmunityTest {
27+
/** character arrays used as immunity lists from Default Encoder.*/
28+
private final static char[] IMMUNE_HTML = { ',', '.', '-', '_', ' ' };
29+
private final static char[] IMMUNE_HTMLATTR = { ',', '.', '-', '_' };
30+
private final static char[] IMMUNE_CSS = {};
31+
private final static char[] IMMUNE_JAVASCRIPT = { ',', '.', '_' };
32+
private final static char[] IMMUNE_VBSCRIPT = { ',', '.', '_' };
33+
private final static char[] IMMUNE_XML = { ',', '.', '-', '_', ' ' };
34+
private final static char[] IMMUNE_SQL = { ' ' };
35+
private final static char[] IMMUNE_OS = { '-' };
36+
private final static char[] IMMUNE_XMLATTR = { ',', '.', '-', '_' };
37+
private final static char[] IMMUNE_XPATH = { ',', '.', '-', '_', ' ' };
38+
private final static char[] IMMUNE_PERCENT = { '%' };
39+
// These are inline in the encode methods, but same principle.
40+
// private final static char[] IMMUNE_LDAP = { '\\', '*', '(', ')', '\0' };
41+
// private final static char[] IMMUNE_DN = { '\\', ',', '+', '"', '<', '>', ';' };
42+
43+
44+
@Parameters(name = "{0}")
45+
public static Collection<Object[]> getParams() {
46+
Collection<Codec> knownCodecs = new ArrayList<Codec>();
47+
knownCodecs.add(new CSSCodec());
48+
knownCodecs.add(new DB2Codec());
49+
knownCodecs.add(new HTMLEntityCodec());
50+
knownCodecs.add(new JavaScriptCodec());
51+
knownCodecs.add(new MySQLCodec(0)); //Standard
52+
knownCodecs.add(new MySQLCodec(1)); //ANSI
53+
knownCodecs.add(new OracleCodec());
54+
knownCodecs.add(new PercentCodec());
55+
knownCodecs.add(new UnixCodec());
56+
knownCodecs.add(new VBScriptCodec());
57+
knownCodecs.add(new WindowsCodec());
58+
knownCodecs.add(new XMLEntityCodec());
59+
60+
// TODO: Add more strings here!!
61+
List<String> sampleStrings = Arrays.asList("%De");
62+
63+
Collection<Object[]> params = new ArrayList<Object[]>();
64+
for (Codec codec : knownCodecs) {
65+
for (String sample : sampleStrings) {
66+
params.add(new Object[]{codec.getClass().getSimpleName() + " " + sample, codec, sample});
67+
}
68+
}
69+
70+
// Add Tests for codecs against the configured ImmunityLists within the Default Encoder.
71+
params.addAll(buildImmunitiyValidation(new HTMLEntityCodec(), IMMUNE_HTML, "IMMUNE_HTML"));
72+
params.addAll(buildImmunitiyValidation(new HTMLEntityCodec(), IMMUNE_XPATH, "IMMUNE_XPATH"));
73+
params.addAll(buildImmunitiyValidation(new HTMLEntityCodec(), IMMUNE_HTMLATTR, "IMMUNE_HTMLATTR"));
74+
params.addAll(buildImmunitiyValidation(new CSSCodec(), IMMUNE_CSS, "IMMUNE_CSS"));
75+
//params.addAll(buildImmunitiyValidation(new DB2Codec(), IMMUNE_HTML, ""));
76+
params.addAll(buildImmunitiyValidation(new JavaScriptCodec(), IMMUNE_JAVASCRIPT, "IMMUNE_JAVASCRIPT"));
77+
params.addAll(buildImmunitiyValidation(new MySQLCodec(0), IMMUNE_SQL, "IMMUNE_SQL"));
78+
params.addAll(buildImmunitiyValidation(new MySQLCodec(1), IMMUNE_SQL, "IMMUNE_SQL"));
79+
params.addAll(buildImmunitiyValidation(new OracleCodec(), IMMUNE_HTML, "IMMUNE_HTML"));
80+
// No standard Immunity char array defined for PercentEncoder, but for
81+
// GitHub issues #306 and $350, we use '%'.
82+
params.addAll(buildImmunitiyValidation(new PercentCodec(), IMMUNE_PERCENT, "IMMUNE_PERCENT"));
83+
params.addAll(buildImmunitiyValidation(new UnixCodec(), IMMUNE_OS, "IMMUNE_OS"));
84+
params.addAll(buildImmunitiyValidation(new VBScriptCodec(), IMMUNE_VBSCRIPT, "IMMUNE_VBSCRIPT"));
85+
params.addAll(buildImmunitiyValidation(new WindowsCodec(), IMMUNE_OS, "IMMUNE_OS"));
86+
params.addAll(buildImmunitiyValidation(new XMLEntityCodec(), IMMUNE_XML, "IMMUNE_XML"));
87+
params.addAll(buildImmunitiyValidation(new XMLEntityCodec(), IMMUNE_XMLATTR, "IMMUNE_XMLATTR"));
88+
89+
params.addAll(fullCharacterCodecValidation(knownCodecs));
90+
91+
return params;
92+
}
93+
94+
private static Collection<Object[]> buildImmunitiyValidation(Codec codec, char[] immunities, String descriptor) {
95+
Collection<Object[]> params = new ArrayList<Object[]>();
96+
for (char c : immunities) {
97+
params.add(new Object[]{codec.getClass().getSimpleName() + " " + descriptor + " ("+ c + ")", codec, String.valueOf(c)});
98+
}
99+
return params;
100+
}
101+
102+
private static Collection<Object[]> fullCharacterCodecValidation(Collection<Codec> codecs) {
103+
char[] holyCowTesting = StringUtilities.union(EncoderConstants.CHAR_ALPHANUMERICS, EncoderConstants.CHAR_SPECIALS);
104+
Collection<Object[]> params = new ArrayList<Object[]>();
105+
for (Codec codec: codecs) {
106+
params.addAll(buildImmunitiyValidation(codec, holyCowTesting, "Full_ALPHA_AND_SPECIALS"));
107+
}
108+
109+
return params;
110+
}
111+
112+
private final Codec codec;
113+
private final String string;
114+
private final char[] immunityList;
115+
116+
public CodecImmunityTest(String ignored, Codec codec, String toTest) {
117+
this.codec = codec;
118+
this.string = toTest;
119+
/**
120+
* The Immunity character array is every character in the String we're testing.
121+
*
122+
*/
123+
this.immunityList = toTest.toCharArray();
124+
}
125+
126+
@Test
127+
public void testImmuneEncode() {
128+
String encoded = codec.encode(immunityList, string);
129+
Assert.assertEquals(string, encoded);
130+
}
131+
/*
132+
@Test
133+
public void testImmuneDecode() {
134+
String decoded = codec.decode(string);
135+
Assert.assertEquals(string, decoded);
136+
}
137+
*/
138+
}

0 commit comments

Comments
 (0)