├── .classpath
├── .gitignore
├── .project
├── README
├── WEB-INF
└── web.xml.snippet
├── build.xml
├── lib
├── javax.servlet.jar
├── junit-4.4.jar
└── mockito-all-1.8.0.jar
├── src
└── com
│ └── slocumbrau
│ └── filter
│ ├── InjectionAttackFilter.java
│ └── InjectionAttackWrapper.java
├── test
└── com
│ └── slocumbrau
│ └── filter
│ ├── AllowedInputTest.java
│ ├── ConfigurationParametersTest.java
│ ├── CookieXSSTest.java
│ ├── EventHandlerInjectionTest.java
│ ├── InjectionAttackFilterTest.java
│ ├── InjectionAttackWrapperTest.java
│ └── SQLInjectionTest.java
└── todo.txt
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | classes
2 | jars
3 | junit
4 | testclasses
5 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | InjectionAttackFilter
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | InjectionAttackFilter is a subclass of HttpServletRequestWrapper that will protect against common sql injection and cross-site scripting attacks.
2 |
3 | The filter will look at inbound request parameters, and remove any suspicious characters, letting the remaining data through. If someone submits a parameter:
4 |
5 | name=""
6 |
7 | your application will see the harmless:
8 |
9 | name="scriptalert('hi!');script"
10 |
11 | I chose to do this because I generally want to have incomplete data rather than no data. Also, there could be some situation where an end user has a name that triggers the filter. In that case, I'd rather have partial legitimate user data rather than none. Future enhancements will allow you to totally block any parameter that is suspicious.
12 |
13 |
14 | It's covered under the MIT license.
15 |
16 | Copyright (c) 2011 Andrew C Slocum
17 |
18 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
21 |
22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/WEB-INF/web.xml.snippet:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 | injectionAttackFilter
9 | com.slocumbrau.filter.InjectionAttackFilter
10 |
11 |
12 |
13 | filter_xss
14 | true
15 |
16 |
17 | filter_sql_injection
18 | true
19 |
20 |
21 |
22 | click_jacking_header
23 | true
24 |
25 |
26 |
27 |
28 | injectionAttackFilter
29 | /*
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/lib/javax.servlet.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acslocum/InjectionAttackFilter/803e3eb85c0c283d81390737153bf3dd0af84770/lib/javax.servlet.jar
--------------------------------------------------------------------------------
/lib/junit-4.4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acslocum/InjectionAttackFilter/803e3eb85c0c283d81390737153bf3dd0af84770/lib/junit-4.4.jar
--------------------------------------------------------------------------------
/lib/mockito-all-1.8.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acslocum/InjectionAttackFilter/803e3eb85c0c283d81390737153bf3dd0af84770/lib/mockito-all-1.8.0.jar
--------------------------------------------------------------------------------
/src/com/slocumbrau/filter/InjectionAttackFilter.java:
--------------------------------------------------------------------------------
1 | package com.slocumbrau.filter;
2 |
3 | import java.io.IOException;
4 |
5 | import javax.servlet.Filter;
6 | import javax.servlet.FilterChain;
7 | import javax.servlet.FilterConfig;
8 | import javax.servlet.ServletException;
9 | import javax.servlet.ServletRequest;
10 | import javax.servlet.ServletResponse;
11 | import javax.servlet.http.HttpServletRequest;
12 | import javax.servlet.http.HttpServletResponse;
13 |
14 | public class InjectionAttackFilter implements Filter {
15 | private static final String X_FRAME_VALUE = "SAMEORIGIN";
16 | private static final String X_FRAME_HEADER = "X-FRAME-OPTIONS";
17 | public static final String FILTER_XSS_PARAM_NAME = "filter_xss";
18 | public static final String FILTER_SQL_INJECTION_PARAM_NAME = "filter_sql_injection";
19 | public static final String CLICK_JACKING_HEADER = "click_jacking_header";
20 | boolean filterXSS = true;
21 | boolean filterSQL = true;
22 | boolean clickJacking = true;
23 |
24 | @Override
25 | public void destroy() {
26 | }
27 |
28 | @Override
29 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
30 | InjectionAttackWrapper wrapper = new InjectionAttackWrapper((HttpServletRequest) servletRequest, filterXSS, filterSQL);
31 | filterClickJack(servletResponse);
32 | filterChain.doFilter(wrapper, servletResponse);
33 | }
34 |
35 | private void filterClickJack(ServletResponse servletResponse) {
36 | if(clickJacking) {
37 | if(servletResponse instanceof HttpServletResponse) {
38 | HttpServletResponse httpServletResponse = (HttpServletResponse)servletResponse;
39 | if(!httpServletResponse.containsHeader(X_FRAME_HEADER)) {
40 | httpServletResponse.addHeader(X_FRAME_HEADER, X_FRAME_VALUE);
41 | }
42 | }
43 | }
44 | }
45 |
46 | @Override
47 | public void init(FilterConfig config) throws ServletException {
48 | String filterXSSParam = config.getInitParameter(FILTER_XSS_PARAM_NAME);
49 | String filterSQLParam = config.getInitParameter(FILTER_SQL_INJECTION_PARAM_NAME);
50 | String clickJackingParam = config.getInitParameter(CLICK_JACKING_HEADER);
51 | filterXSS = new Boolean(filterXSSParam);
52 | filterSQL = new Boolean(filterSQLParam);
53 | clickJacking = new Boolean(clickJackingParam);
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/com/slocumbrau/filter/InjectionAttackWrapper.java:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2011 Andrew C Slocum
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | **/
10 |
11 | package com.slocumbrau.filter;
12 |
13 | import java.util.HashMap;
14 | import java.util.Map;
15 | import java.util.Set;
16 |
17 | import javax.servlet.http.Cookie;
18 | import javax.servlet.http.HttpServletRequest;
19 | import javax.servlet.http.HttpServletRequestWrapper;
20 |
21 | public class InjectionAttackWrapper extends HttpServletRequestWrapper {
22 | private static final String EVENTS = "((?i)onload|onunload|onchange|onsubmit|onreset" + "|onselect|onblur|onfocus|onkeydown|onkeypress|onkeyup"
23 | + "|onclick|ondblclick|onmousedown|onmousemove|onmouseout|onmouseover|onmouseup)";
24 | private static final String XSS_HTML_TAG = "(%3C)|(%3E)|[<>]+";
25 | private static final String XSS_INJECTION = "((%22%20)|(%22\\s)|('%22)|(%22\\+))\\w.*|(\\s|%20)" + EVENTS + ".*|(%3D)|(%7C)";
26 | private static final String XSS_REGEX = XSS_HTML_TAG + "|" + XSS_INJECTION;
27 | private static final String SQL_REGEX = "('.+--)|(--)|(\\|)|(%7C)";
28 |
29 | boolean filterXSS = true;
30 | boolean filterSQL = true;
31 |
32 | public InjectionAttackWrapper(HttpServletRequest request, boolean filterXSS, boolean filterSQL) {
33 | super(request);
34 | this.filterXSS = filterXSS;
35 | this.filterSQL = filterSQL;
36 | }
37 |
38 | public InjectionAttackWrapper(HttpServletRequest request) {
39 | this(request,true,true);
40 | }
41 |
42 |
43 | @Override
44 | public String getParameter(String name) {
45 | String value = super.getParameter(name);
46 | return filterParamString(value);
47 | }
48 |
49 | @Override
50 | public Map getParameterMap() {
51 | Map rawMap = super.getParameterMap();
52 | Map filteredMap = new HashMap(rawMap.size());
53 | Set keys = rawMap.keySet();
54 | for (String key : keys) {
55 | String[] rawValue = rawMap.get(key);
56 | String[] filteredValue = filterStringArray(rawValue);
57 | filteredMap.put(key, filteredValue);
58 | }
59 | return filteredMap;
60 | }
61 |
62 | protected String[] filterStringArray(String[] rawValue) {
63 | String[] filteredArray = new String[rawValue.length];
64 | for (int i = 0; i < rawValue.length; i++) {
65 | filteredArray[i] = filterParamString(rawValue[i]);
66 | }
67 | return filteredArray;
68 | }
69 |
70 | @Override
71 | public String[] getParameterValues(String name) {
72 | String[] rawValues = super.getParameterValues(name);
73 | if (rawValues == null)
74 | return null;
75 | String[] filteredValues = new String[rawValues.length];
76 | for (int i = 0; i < rawValues.length; i++) {
77 | filteredValues[i] = filterParamString(rawValues[i]);
78 | }
79 | return filteredValues;
80 | }
81 |
82 | protected String filterParamString(String rawValue) {
83 | if (rawValue == null) {
84 | return null;
85 | }
86 | if (filterXSS()) {
87 | rawValue = rawValue.replaceAll(XSS_REGEX, "");
88 | }
89 | if (filterSQL()) {
90 | rawValue = rawValue.replaceAll(SQL_REGEX, "");
91 | }
92 | return rawValue;
93 | }
94 |
95 |
96 | @Override
97 | public Cookie[] getCookies() {
98 | Cookie[] existingCookies = super.getCookies();
99 | if(existingCookies != null) {
100 | for(int i=0;i innocuousMap = new HashMap();
18 | Map injectionMap = new HashMap();
19 |
20 | @Before
21 | public void setUp() throws Exception {
22 | request = Mockito.mock(HttpServletRequest.class);
23 | wrapper = new InjectionAttackWrapper(request);
24 | innocuousMap.put("param1", new String[] { "%20Christina Zhong" });
25 | innocuousMap.put("param2", new String[] { "%20ona sunny day" });
26 | innocuousMap.put("param3", new String[] { "%20on a rainy day" });
27 | innocuousMap.put("param4", new String[] { "Then ona winter day" });
28 |
29 | String injectedCodeWithHexspace = "%20onMouseOver=alert('today');";
30 | String injectedCodeWithHexquote = "%22%20string";
31 | String injectedCodeWithSpace = " onMouseOver=alert('today');";
32 | String injectedCodeWithQuote = "' string";
33 | String injectedCodeKeyboardWithSpace = " onkeydown=alert('today');";
34 | String injectedCodeWithHexspaceAndSpace = "%22+onmouseover=alert(document.cookie)+%22";
35 | injectionMap.put("param1", new String[] { injectedCodeWithHexspace });
36 | injectionMap.put("param2", new String[] { injectedCodeWithHexquote });
37 | injectionMap.put("param3", new String[] { injectedCodeWithSpace });
38 | injectionMap.put("param4", new String[] { injectedCodeWithQuote });
39 | injectionMap.put("param5", new String[] { injectedCodeKeyboardWithSpace });
40 | injectionMap.put("param6", new String[] { injectedCodeWithHexspaceAndSpace });
41 | }
42 |
43 | @Test
44 | public void shouldNotFilterMessageWithAnOnInAName() {
45 | Mockito.when(request.getParameterMap()).thenReturn(innocuousMap);
46 |
47 | wrapper = new InjectionAttackWrapper(request);
48 | Map output = wrapper.getParameterMap();
49 | assertEquals("%20Christina Zhong", output.get("param1")[0]);
50 |
51 | }
52 |
53 | @Test
54 | public void shouldNotFilterMessageWithStartingWithOn() {
55 | Mockito.when(request.getParameterMap()).thenReturn(innocuousMap);
56 |
57 | wrapper = new InjectionAttackWrapper(request);
58 | Map output = wrapper.getParameterMap();
59 | assertEquals("%20ona sunny day", output.get("param2")[0]);
60 |
61 | }
62 |
63 | @Test
64 | public void shouldNotFilterMessageWithAnOnInItLaterInTheString() {
65 | Mockito.when(request.getParameterMap()).thenReturn(innocuousMap);
66 |
67 | wrapper = new InjectionAttackWrapper(request);
68 | Map output = wrapper.getParameterMap();
69 | assertEquals("Then ona winter day", output.get("param4")[0]);
70 |
71 | }
72 |
73 | @Test
74 | public void shouldNotFilterMessageStartingWithOn() {
75 | Mockito.when(request.getParameterMap()).thenReturn(innocuousMap);
76 |
77 | wrapper = new InjectionAttackWrapper(request);
78 | Map output = wrapper.getParameterMap();
79 | assertEquals("%20on a rainy day", output.get("param3")[0]);
80 |
81 | }
82 |
83 | @Test
84 | public void shouldFilterInjectedCodeWithHexspace() {
85 | Mockito.when(request.getParameterMap()).thenReturn(injectionMap);
86 | wrapper = new InjectionAttackWrapper(request);
87 | Map output = wrapper.getParameterMap();
88 |
89 | assertEquals("", ((String[]) output.get("param1"))[0]);
90 | }
91 |
92 | @Test
93 | public void shouldFilterInjectedCodeWithHexquote() {
94 | Mockito.when(request.getParameterMap()).thenReturn(injectionMap);
95 | wrapper = new InjectionAttackWrapper(request);
96 | Map output = wrapper.getParameterMap();
97 |
98 | assertEquals("", ((String[]) output.get("param2"))[0]);
99 | }
100 |
101 | @Test
102 | public void shouldFilterInjectedCodeWithSpace() {
103 | Mockito.when(request.getParameterMap()).thenReturn(injectionMap);
104 | wrapper = new InjectionAttackWrapper(request);
105 | Map output = wrapper.getParameterMap();
106 |
107 | assertEquals("", ((String[]) output.get("param3"))[0]);
108 | }
109 |
110 | @Test
111 | public void shouldNotFilterQuoteSpace() {
112 | Mockito.when(request.getParameterMap()).thenReturn(injectionMap);
113 | wrapper = new InjectionAttackWrapper(request);
114 | Map output = wrapper.getParameterMap();
115 |
116 | assertEquals("' string", ((String[]) output.get("param4"))[0]);
117 | }
118 |
119 | @Test
120 | public void shouldNotFilterInjectedCodeKeyboardWithSpace() {
121 | Mockito.when(request.getParameterMap()).thenReturn(injectionMap);
122 | wrapper = new InjectionAttackWrapper(request);
123 | Map output = wrapper.getParameterMap();
124 |
125 | assertEquals("", ((String[]) output.get("param5"))[0]);
126 | }
127 |
128 | @Test
129 | public void shouldFilterInjectedCodeHexQuoteWithNormalSpace() {
130 | Mockito.when(request.getParameterMap()).thenReturn(injectionMap);
131 | wrapper = new InjectionAttackWrapper(request);
132 | Map output = wrapper.getParameterMap();
133 |
134 | assertEquals("", ((String[]) output.get("param6"))[0]);
135 | }
136 |
137 | }
--------------------------------------------------------------------------------
/test/com/slocumbrau/filter/InjectionAttackFilterTest.java:
--------------------------------------------------------------------------------
1 | package com.slocumbrau.filter;
2 |
3 | import static org.junit.Assert.assertTrue;
4 | import static org.junit.Assert.assertFalse;
5 |
6 | import javax.servlet.FilterChain;
7 | import javax.servlet.FilterConfig;
8 | import javax.servlet.ServletRequest;
9 | import javax.servlet.ServletResponse;
10 | import javax.servlet.http.HttpServletRequest;
11 | import javax.servlet.http.HttpServletResponse;
12 |
13 | import org.junit.Test;
14 | import org.mockito.Mockito;
15 |
16 | public class InjectionAttackFilterTest {
17 | @Test
18 | public void shouldSetFilterXSSToTrueWhenParamIsSetTrue() throws Exception {
19 | FilterConfig filterConfig = Mockito.mock(FilterConfig.class);
20 | Mockito.when(filterConfig.getInitParameter(InjectionAttackFilter.FILTER_XSS_PARAM_NAME)).thenReturn("true");
21 | InjectionAttackFilter filter = new InjectionAttackFilter();
22 | filter.init(filterConfig);
23 | assertTrue(filter.filterXSS);
24 | }
25 |
26 | @Test
27 | public void shouldSetFilterXSSToFalseWhenParamIsSetFalse() throws Exception {
28 | FilterConfig filterConfig = Mockito.mock(FilterConfig.class);
29 | Mockito.when(filterConfig.getInitParameter(InjectionAttackFilter.FILTER_XSS_PARAM_NAME)).thenReturn("false");
30 | InjectionAttackFilter filter = new InjectionAttackFilter();
31 | filter.init(filterConfig);
32 | assertFalse(filter.filterXSS);
33 | }
34 |
35 | @Test
36 | public void shouldSetFilterSQLToTrueWhenParamIsSetTrue() throws Exception {
37 | FilterConfig filterConfig = Mockito.mock(FilterConfig.class);
38 | Mockito.when(filterConfig.getInitParameter(InjectionAttackFilter.FILTER_SQL_INJECTION_PARAM_NAME)).thenReturn("true");
39 | InjectionAttackFilter filter = new InjectionAttackFilter();
40 | filter.init(filterConfig);
41 | assertTrue(filter.filterSQL);
42 | }
43 |
44 | @Test
45 | public void shouldSetFilterSQLToFalseWhenParamIsSetFalse() throws Exception {
46 | FilterConfig filterConfig = Mockito.mock(FilterConfig.class);
47 | Mockito.when(filterConfig.getInitParameter(InjectionAttackFilter.FILTER_SQL_INJECTION_PARAM_NAME)).thenReturn("false");
48 | InjectionAttackFilter filter = new InjectionAttackFilter();
49 | filter.init(filterConfig);
50 | assertFalse(filter.filterSQL);
51 | }
52 |
53 | @Test
54 | public void shouldAddXFrameOptionsHeaderWhenNotPresent() throws Exception {
55 | FilterConfig filterConfig = Mockito.mock(FilterConfig.class);
56 | Mockito.when(filterConfig.getInitParameter(InjectionAttackFilter.CLICK_JACKING_HEADER)).thenReturn("true");
57 | InjectionAttackFilter filter = new InjectionAttackFilter();
58 | filter.init(filterConfig);
59 | HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
60 | Mockito.when(response.containsHeader("X-FRAME-OPTIONS")).thenReturn(false);
61 | filter.doFilter(Mockito.mock(HttpServletRequest.class), response, Mockito.mock(FilterChain.class));
62 | Mockito.verify(response).addHeader("X-FRAME-OPTIONS", "SAMEORIGIN");
63 | }
64 |
65 | @Test
66 | public void shouldNotAddXFrameOptionsHeaderWhenAlreadyPresent() throws Exception {
67 | FilterConfig filterConfig = Mockito.mock(FilterConfig.class);
68 | Mockito.when(filterConfig.getInitParameter(InjectionAttackFilter.CLICK_JACKING_HEADER)).thenReturn("true");
69 | InjectionAttackFilter filter = new InjectionAttackFilter();
70 | filter.init(filterConfig);
71 | HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
72 | Mockito.when(response.containsHeader("X-FRAME-OPTIONS")).thenReturn(true);
73 | filter.doFilter(Mockito.mock(HttpServletRequest.class), response, Mockito.mock(FilterChain.class));
74 | Mockito.verify(response, Mockito.never()).addHeader("X-FRAME-OPTIONS", "SAMEORIGIN");
75 | }
76 |
77 | @Test
78 | public void shouldNotAddXFrameOptionsHeaderWhenDisabled() throws Exception {
79 | FilterConfig filterConfig = Mockito.mock(FilterConfig.class);
80 | Mockito.when(filterConfig.getInitParameter(InjectionAttackFilter.CLICK_JACKING_HEADER)).thenReturn("false");
81 | InjectionAttackFilter filter = new InjectionAttackFilter();
82 | filter.init(filterConfig);
83 | HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
84 | Mockito.when(response.containsHeader("X-FRAME-OPTIONS")).thenReturn(false);
85 | filter.doFilter(Mockito.mock(HttpServletRequest.class), response, Mockito.mock(FilterChain.class));
86 | Mockito.verify(response, Mockito.never()).addHeader("X-FRAME-OPTIONS", "SAMEORIGIN");
87 | }
88 |
89 | @Test
90 | public void falseShouldParseFalse() {
91 | assertFalse( new Boolean("false") );
92 | }
93 |
94 | @Test
95 | public void trueShouldParseTrue() {
96 | assertTrue( new Boolean("true") );
97 | }
98 |
99 | }
--------------------------------------------------------------------------------
/test/com/slocumbrau/filter/InjectionAttackWrapperTest.java:
--------------------------------------------------------------------------------
1 | package com.slocumbrau.filter;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 | import javax.servlet.http.HttpServletRequest;
9 |
10 | import org.junit.Before;
11 | import org.junit.Ignore;
12 | import org.junit.Test;
13 | import org.mockito.Mockito;
14 |
15 | public class InjectionAttackWrapperTest {
16 | private final String DATE_INPUT = "August 30, 2005";
17 | private final String OTHER_CHARS_INPUT = ".' ,-";
18 | private final String STRING_WITH_RESTRICTED_CHARS = "";
19 | private final String MIXED_CASE_STRING="en_SG_AP---->";
20 | private final String RESTRICTED_2 = "%3Cscript%3Efoo%3C/script%3E";
21 | private final String RESTRICTED_LIST = "=%<>|$;%\"\n\r\\hi";
22 | private final String FILTERED_STRING = "scriptfoo/script";
23 | private InjectionAttackWrapper wrapper;
24 | private HttpServletRequest request;
25 |
26 | @Before
27 | public void setUp() throws Exception {
28 | request = Mockito.mock(HttpServletRequest.class);
29 | wrapper = new InjectionAttackWrapper(request);
30 | }
31 |
32 | @Test
33 | public void shouldStopScriptlets() {
34 | assertEquals(FILTERED_STRING, wrapper.filterParamString((STRING_WITH_RESTRICTED_CHARS)));
35 | }
36 |
37 | @Test
38 | public void shouldStopEscapedScriptlets() {
39 | assertEquals(FILTERED_STRING, wrapper.filterParamString((RESTRICTED_2)));
40 | }
41 |
42 | @Test
43 | public void shouldFilterLinkInjection() {
44 | assertEquals("%22%27A%20HREF%22%2FWF_XSRF.html%22Injected%20Link%2FA",
45 | wrapper.filterParamString("%22%27%3E%3CA%20HREF%3D%22%2FWF_XSRF.html%22%3EInjected%20Link%3C%2FA%3E"));
46 | }
47 |
48 | @Test
49 | public void shouldFilterEscapedEquals() {
50 | assertEquals("hi", wrapper.filterParamString("%3Dhi"));
51 | }
52 |
53 | @Test
54 | public void shouldFilterCSSInjection() {
55 | assertEquals("something", wrapper.filterParamString("something%22%20style%3D%22background:url(javascript:alert(234))%22%20OA%3D%22"));
56 | }
57 |
58 | @Test
59 | @Ignore
60 | public void shouldRemoveLotsOfBadCharacters() {
61 | assertEquals("hi", wrapper.filterParamString(RESTRICTED_LIST));
62 | }
63 |
64 | @Test
65 | public void shouldCatchMixesCaseScriptTags() {
66 | assertEquals("en_SG_APsCrIpTalert(45152)/sCrIpT", wrapper.filterParamString(MIXED_CASE_STRING));
67 | }
68 |
69 | @Test
70 | public void shouldFiltersRestrictedCharsAndSkipsRegularCharsInArray() {
71 | String[] array = new String[] { STRING_WITH_RESTRICTED_CHARS, DATE_INPUT, OTHER_CHARS_INPUT };
72 |
73 | assertEquals(FILTERED_STRING, wrapper.filterStringArray(array)[0]);
74 | assertEquals(DATE_INPUT, wrapper.filterStringArray(array)[1]);
75 | assertEquals(OTHER_CHARS_INPUT, wrapper.filterStringArray(array)[2]);
76 | }
77 |
78 | @Test
79 | public void shouldFilterParameterMap() {
80 | Map map = new HashMap();
81 | final String param1 = "param1";
82 | map.put(param1, new String[] { STRING_WITH_RESTRICTED_CHARS });
83 | final String param2 = "param2";
84 | map.put(param2, new String[] { DATE_INPUT });
85 |
86 | Mockito.when(request.getParameterMap()).thenReturn(map);
87 |
88 | wrapper = new InjectionAttackWrapper(request);
89 | Map output = wrapper.getParameterMap();
90 |
91 | assertEquals(FILTERED_STRING, ((String[]) output.get(param1))[0]);
92 | assertEquals(DATE_INPUT, ((String[]) output.get(param2))[0]);
93 | }
94 |
95 | @Test
96 | public void shouldFilterEntireQueryString() {
97 | String xssString = "orderNumber=&phoneNumber=>'>";
98 | Mockito.when(request.getQueryString()).thenReturn(xssString);
99 | wrapper = new InjectionAttackWrapper(request);
100 | assertEquals("orderNumber=&phoneNumber='scriptalert('boooo')/script", wrapper.getQueryString());
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/test/com/slocumbrau/filter/SQLInjectionTest.java:
--------------------------------------------------------------------------------
1 | package com.slocumbrau.filter;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import javax.servlet.http.HttpServletRequest;
6 |
7 | import org.junit.Before;
8 | import org.junit.Test;
9 | import org.mockito.Mockito;
10 |
11 | public class SQLInjectionTest {
12 | private final String SQL_INJECTION_ENCODED = "%27%20%7C%7C%20%27foo";
13 | private final String SQL_INJECTION_UNENCODED = "' || 'foo";
14 |
15 | private InjectionAttackWrapper wrapper;
16 | private HttpServletRequest request;
17 |
18 | @Before
19 | public void setUp() throws Exception {
20 | request = Mockito.mock(HttpServletRequest.class);
21 | wrapper = new InjectionAttackWrapper(request);
22 | }
23 |
24 | @Test
25 | public void shouldCatchSqlStrings() {
26 | assertEquals("", wrapper.filterParamString("'select * from users;--"));
27 | }
28 |
29 | @Test
30 | public void shouldFilterEncodedPipes() {
31 | assertEquals("%27%20%20%27foo", wrapper.filterParamString(SQL_INJECTION_ENCODED));
32 | }
33 |
34 | @Test
35 | public void shouldFilterUnencodedPipes() {
36 | assertEquals("' 'foo", wrapper.filterParamString(SQL_INJECTION_UNENCODED));
37 | }
38 |
39 | }
--------------------------------------------------------------------------------
/todo.txt:
--------------------------------------------------------------------------------
1 | allow user-configured additional string
2 | strip bad chars vs blank entire string
3 | optional logging (log4j?)
--------------------------------------------------------------------------------