1 /*--
2 Copyright (C) 2005 Tim Solley.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "Deadbolt" may be used to endorse or promote products
18 derived from this software without prior written permission.
19
20 4. Products derived from this software may not be called "Deadbolt", nor
21 may "Deadbolt" appear in their name, without prior written permission
22 from the Deadbolt Project Management timsolley@yahoo.com.
23
24 In addition, we request (but do not require) that you include in the
25 end-user documentation provided with the redistribution and/or in the
26 software itself an acknowledgement equivalent to the following:
27 "This product includes software developed by the
28 Deadbolt Project (http://deadbolt.sourceforge.net/)."
29 Alternatively, the acknowledgment may be graphical using the logos
30 available at http://deadbolt.sourceforge.net.
31
32 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
33 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
34 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35 DISCLAIMED. IN NO EVENT SHALL THE DEADBOLT AUTHORS OR THE PROJECT
36 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
37 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
38 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
39 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
40 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
41 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
42 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 SUCH DAMAGE.
44
45 This software consists of voluntary contributions made by many
46 individuals on behalf of the Deadbolt Project and was originally
47 created by Tim Solley timsolley@yahoo.com. For more information
48 on the Deadbolt Project, please see <http://deadbolt.sourceforge.net/>.
49 */
50 package net.sf.deadbolt.handlers;
51
52
53
54 import java.util.*;
55
56 import javax.servlet.http.HttpServletRequest;
57 import javax.servlet.http.HttpServletResponse;
58
59 import net.sf.deadbolt.model.Room;
60
61 import org.apache.log4j.Logger;
62
63 /***
64 * This class will secure a Room from SQL injection attacks.
65 *
66 * @author Tim Solley <timsolley@yahoo.com>
67 */
68 public class SQLInjectionHandler extends DeadboltHandler {
69 private static Logger logger = Logger.getLogger(SQLInjectionHandler.class.getName());
70
71 /***
72 * These are all the keywords that this handler will check for
73 */
74 private String[] badStringsWeak = new String[] {"'", ";", "--"};
75
76 private String[] badStringsStrong = new String[] {"'", ";", "--", "union", "drop", "insert",
77 "update", "delete", "having", "group by", "select", "sum", "max", "min",
78 "values", "@@", "from", "where", "create", "begin", "declare", "end",
79 "exec", "shutdown", "xp_", "master", "bulk insert"};
80 private String[] badStrings;
81
82 private List excludedFields;
83
84 /***
85 * This method runs through the parameters in the request and checks them
86 * for the keywords that are not allowed.
87 */
88 public boolean authenticate(HttpServletRequest request,
89 HttpServletResponse response, Room room) {
90 logger.debug("ENTERING: authenticate");
91
92 boolean result = true;
93
94 /* Check for the existence of the "LEVEL" init param specifying the
95 * security level from this room. If the level is strong, we'll check
96 * for an expanded set of keywords. This is primarily for large
97 * text fields and the like where some of the strong keywords would
98 * be valid.
99 */
100 if("WEAK".equals(room.getInitParam("LEVEL"))) {
101 badStrings = badStringsWeak;
102 } else {
103 badStrings = badStringsStrong;
104 }
105
106 // Check for any excluded fields
107 String excludedFieldsParam = room.getInitParam("EXCLUDED-FIELDS");
108 logger.debug("The following fields will be excluded from this handler: " + excludedFieldsParam);
109 if(excludedFieldsParam != null) {
110 String[] excludedFieldsArray = excludedFieldsParam.split(",");
111 for(int i = 0; i < excludedFieldsArray.length; i++) {
112 excludedFieldsArray[i] = excludedFieldsArray[i].trim();
113 }
114 excludedFields = Arrays.asList(excludedFieldsArray);
115 }
116 else
117 excludedFields = new ArrayList(0);
118
119 for(Enumeration parameterEnumeration = request.getParameterNames();
120 parameterEnumeration.hasMoreElements();) {
121 String element = (String) parameterEnumeration.nextElement();
122 if(!excludedFields.contains(element)) {
123 logger.debug("The following parameter is being tested: " + element);
124 result = testValue(request.getParameter(element), request, room);
125 }
126
127 if(!result) {
128 break;
129 }
130 }
131
132 logger.debug("EXITING: authenticate");
133 return result;
134 }
135
136 /***
137 * This method scans the parameter value sent in, checking for the
138 * prohibited strings.
139 *
140 * @param value
141 * @param request
142 * @param room
143 * @return
144 */
145 private boolean testValue(String value, HttpServletRequest request, Room room) {
146 logger.debug("ENTERING: testValue");
147 boolean result = true;
148 // Loop over the array of bad strings and check each one against the
149 // current request parameter
150 for(int key = 0; key < badStrings.length; key++) {
151 logger.debug("Testing value = " + value + " and badString = " + badStrings[key]);
152 if(value.matches(badStrings[key])) {
153 logger.debug("A forbidden string was found: " + value);
154 addErrorMessage(request, (String) room.getInitParam("ErrorMessage"));
155 logger.debug("The value was rejected, returning false");
156 result = false;
157 break;
158 }
159 }
160
161 logger.debug("EXITING: testValue");
162 return result;
163 }
164
165 }