001
014
015 package com.liferay.portal.kernel.servlet;
016
017 import com.liferay.portal.kernel.util.CharPool;
018 import com.liferay.portal.kernel.util.GetterUtil;
019 import com.liferay.portal.kernel.util.HttpUtil;
020 import com.liferay.portal.kernel.util.KeyValuePair;
021 import com.liferay.portal.kernel.util.PropsKeys;
022 import com.liferay.portal.kernel.util.PropsUtil;
023 import com.liferay.portal.kernel.util.ServerDetector;
024 import com.liferay.portal.kernel.util.SortedProperties;
025 import com.liferay.portal.kernel.util.StringPool;
026 import com.liferay.portal.kernel.util.StringUtil;
027 import com.liferay.portal.kernel.util.Validator;
028
029 import java.io.IOException;
030
031 import java.util.ArrayList;
032 import java.util.Comparator;
033 import java.util.List;
034 import java.util.Map;
035 import java.util.Properties;
036
037 import javax.servlet.http.HttpServletRequest;
038 import javax.servlet.http.HttpServletResponse;
039 import javax.servlet.http.HttpServletResponseWrapper;
040
041
046 public class SanitizedServletResponse extends HttpServletResponseWrapper {
047
048 public static HttpServletResponse getSanitizedServletResponse(
049 HttpServletRequest request, HttpServletResponse response) {
050
051 setXContentOptions(request, response);
052 setXFrameOptions(request, response);
053 setXXSSProtection(request, response);
054
055 if (ServerDetector.isResin()) {
056 response = new SanitizedServletResponse(response);
057 }
058
059 return response;
060 }
061
062 @Override
063 public void addHeader(String name, String value) {
064 super.addHeader(
065 HttpUtil.sanitizeHeader(name), HttpUtil.sanitizeHeader(value));
066 }
067
068 @Override
069 public void sendRedirect(String location) throws IOException {
070 super.sendRedirect(HttpUtil.sanitizeHeader(location));
071 }
072
073 @Override
074 public void setCharacterEncoding(String charset) {
075 super.setCharacterEncoding(HttpUtil.sanitizeHeader(charset));
076 }
077
078 @Override
079 public void setContentType(String type) {
080 super.setContentType(HttpUtil.sanitizeHeader(type));
081 }
082
083 @Override
084 public void setHeader(String name, String value) {
085 super.setHeader(
086 HttpUtil.sanitizeHeader(name), HttpUtil.sanitizeHeader(value));
087 }
088
089 protected static void setXContentOptions(
090 HttpServletRequest request, HttpServletResponse response) {
091
092 if (!_X_CONTENT_TYPE_OPTIONS) {
093 return;
094 }
095
096 if (_X_CONTENT_TYPE_OPTIONS_URLS_EXCLUDES.length > 0) {
097 String requestURI = request.getRequestURI();
098
099 for (String url : _X_CONTENT_TYPE_OPTIONS_URLS_EXCLUDES) {
100 if (requestURI.startsWith(url)) {
101 return;
102 }
103 }
104 }
105
106 response.setHeader(HttpHeaders.X_CONTENT_TYPE_OPTIONS, "nosniff");
107 }
108
109 protected static void setXFrameOptions(
110 HttpServletRequest request, HttpServletResponse response) {
111
112 if (!_X_FRAME_OPTIONS) {
113 return;
114 }
115
116 String requestURI = request.getRequestURI();
117
118 for (KeyValuePair xFrameOptionKVP : _xFrameOptionKVPs) {
119 String url = xFrameOptionKVP.getKey();
120 String value = xFrameOptionKVP.getValue();
121
122 if (requestURI.startsWith(url)) {
123 if (value != null) {
124 response.setHeader(
125 HttpHeaders.X_FRAME_OPTIONS,
126 xFrameOptionKVP.getValue());
127 }
128
129 return;
130 }
131 }
132
133 response.setHeader(HttpHeaders.X_FRAME_OPTIONS, "DENY");
134 }
135
136 protected static void setXXSSProtection(
137 HttpServletRequest request, HttpServletResponse response) {
138
139 if (!_X_XSS_PROTECTION) {
140 return;
141 }
142
143 response.setHeader(HttpHeaders.X_XSS_PROTECTION, "1; mode=block");
144 }
145
146 private SanitizedServletResponse(HttpServletResponse response) {
147 super(response);
148 }
149
150 private static final boolean _X_CONTENT_TYPE_OPTIONS =
151 GetterUtil.getBoolean(
152 PropsUtil.get(PropsKeys.HTTP_HEADER_SECURE_X_CONTENT_TYPE_OPTIONS),
153 true);
154
155 private static final String[] _X_CONTENT_TYPE_OPTIONS_URLS_EXCLUDES =
156 PropsUtil.getArray(
157 PropsKeys.HTTP_HEADER_SECURE_X_CONTENT_TYPE_OPTIONS_URLS_EXCLUDES);
158
159 private static final boolean _X_FRAME_OPTIONS;
160
161 private static final boolean _X_XSS_PROTECTION = GetterUtil.getBoolean(
162 PropsUtil.get(PropsKeys.HTTP_HEADER_SECURE_X_XSS_PROTECTION), true);
163
164 private static final KeyValuePair[] _xFrameOptionKVPs;
165
166 static {
167 Properties properties = new SortedProperties(
168 new Comparator<String>() {
169
170 @Override
171 public int compare(String key1, String key2) {
172 return GetterUtil.getIntegerStrict(key1) -
173 GetterUtil.getIntegerStrict(key2);
174 }
175
176 },
177 PropsUtil.getProperties(
178 PropsKeys.HTTP_HEADER_SECURE_X_FRAME_OPTIONS +
179 StringPool.PERIOD,
180 true));
181
182 List<KeyValuePair> xFrameOptionKVPs = new ArrayList<KeyValuePair>(
183 properties.size());
184
185 for (Map.Entry<Object, Object> entry : properties.entrySet()) {
186 String propertyValue = (String)entry.getValue();
187
188 String[] propertyValueParts = StringUtil.split(
189 propertyValue, CharPool.PIPE);
190
191 if (propertyValueParts.length > 2) {
192 continue;
193 }
194
195 String url = StringUtil.trim(propertyValueParts[0]);
196
197 if (Validator.isNull(url)) {
198 continue;
199 }
200
201 if (propertyValueParts.length == 1) {
202 xFrameOptionKVPs.add(new KeyValuePair(url, null));
203
204 continue;
205 }
206
207 String value = StringUtil.trim(propertyValueParts[1]);
208
209 if (Validator.isNull(value)) {
210 value = null;
211 }
212
213 xFrameOptionKVPs.add(new KeyValuePair(url, value));
214 }
215
216 _xFrameOptionKVPs = xFrameOptionKVPs.toArray(
217 new KeyValuePair[xFrameOptionKVPs.size()]);
218
219 if (_xFrameOptionKVPs.length == 0) {
220 _X_FRAME_OPTIONS = false;
221 }
222 else {
223 _X_FRAME_OPTIONS = GetterUtil.getBoolean(
224 PropsUtil.get(PropsKeys.HTTP_HEADER_SECURE_X_FRAME_OPTIONS),
225 true);
226 }
227 }
228
229 }