/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.kernel.servlet;
import com.liferay.portal.kernel.util.CharPool;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.HttpUtil;
import com.liferay.portal.kernel.util.KeyValuePair;
import com.liferay.portal.kernel.util.PortalUtil;
import com.liferay.portal.kernel.util.PropertiesUtil;
import com.liferay.portal.kernel.util.ServerDetector;
import com.liferay.portal.kernel.util.SortedProperties;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.SystemProperties;
import com.liferay.portal.kernel.util.Validator;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.servlet.http.HttpSession;
/**
* @author László Csontos
* @author Shuyang Zhou
* @author Tomas Polesovsky
*/
public class SanitizedServletResponse extends HttpServletResponseWrapper {
public static void disableXSSAuditor(HttpServletResponse response) {
response.setHeader(HttpHeaders.X_XSS_PROTECTION, "0");
}
public static void disableXSSAuditor(PortletResponse portletResponse) {
disableXSSAuditor(PortalUtil.getHttpServletResponse(portletResponse));
}
public static void disableXSSAuditorOnNextRequest(
HttpServletRequest request) {
HttpSession session = request.getSession();
session.setAttribute(_DISABLE_XSS_AUDITOR, Boolean.TRUE);
}
public static void disableXSSAuditorOnNextRequest(
PortletRequest portletRequest) {
disableXSSAuditorOnNextRequest(
PortalUtil.getHttpServletRequest(portletRequest));
}
public static HttpServletResponse getSanitizedServletResponse(
HttpServletRequest request, HttpServletResponse response) {
setXContentOptions(request, response);
setXFrameOptions(request, response);
setXXSSProtection(request, response);
if (ServerDetector.isResin()) {
response = new SanitizedServletResponse(response);
}
return response;
}
@Override
public void addHeader(String name, String value) {
super.addHeader(
HttpUtil.sanitizeHeader(name), HttpUtil.sanitizeHeader(value));
}
@Override
public void sendRedirect(String location) throws IOException {
super.sendRedirect(HttpUtil.sanitizeHeader(location));
}
@Override
public void setCharacterEncoding(String charset) {
super.setCharacterEncoding(HttpUtil.sanitizeHeader(charset));
}
@Override
public void setContentType(String type) {
super.setContentType(HttpUtil.sanitizeHeader(type));
}
@Override
public void setHeader(String name, String value) {
super.setHeader(
HttpUtil.sanitizeHeader(name), HttpUtil.sanitizeHeader(value));
}
protected static void setXContentOptions(
HttpServletRequest request, HttpServletResponse response) {
if (!_X_CONTENT_TYPE_OPTIONS) {
return;
}
if (_X_CONTENT_TYPE_OPTIONS_URLS_EXCLUDES.length > 0) {
String requestURI = request.getRequestURI();
for (String url : _X_CONTENT_TYPE_OPTIONS_URLS_EXCLUDES) {
if (requestURI.startsWith(url)) {
return;
}
}
}
response.setHeader(HttpHeaders.X_CONTENT_TYPE_OPTIONS, "nosniff");
}
protected static void setXFrameOptions(
HttpServletRequest request, HttpServletResponse response) {
if (!_X_FRAME_OPTIONS) {
return;
}
String requestURI = request.getRequestURI();
for (KeyValuePair xFrameOptionKVP : _xFrameOptionKVPs) {
String url = xFrameOptionKVP.getKey();
String value = xFrameOptionKVP.getValue();
if (requestURI.startsWith(url)) {
if (value != null) {
response.setHeader(
HttpHeaders.X_FRAME_OPTIONS,
xFrameOptionKVP.getValue());
}
return;
}
}
response.setHeader(HttpHeaders.X_FRAME_OPTIONS, "DENY");
}
protected static void setXXSSProtection(
HttpServletRequest request, HttpServletResponse response) {
HttpSession session = request.getSession(false);
if ((session != null) &&
(session.getAttribute(_DISABLE_XSS_AUDITOR) != null)) {
session.removeAttribute(_DISABLE_XSS_AUDITOR);
response.setHeader(HttpHeaders.X_XSS_PROTECTION, "0");
return;
}
if (_X_XSS_PROTECTION == null) {
return;
}
response.setHeader(HttpHeaders.X_XSS_PROTECTION, _X_XSS_PROTECTION);
}
private SanitizedServletResponse(HttpServletResponse response) {
super(response);
}
private static final String _DISABLE_XSS_AUDITOR =
SanitizedServletResponse.class.getName() + "DISABLE_XSS_AUDITOR";
private static final boolean _X_CONTENT_TYPE_OPTIONS =
GetterUtil.getBoolean(
SystemProperties.get("http.header.secure.x.content.type.options"),
true);
private static final String[] _X_CONTENT_TYPE_OPTIONS_URLS_EXCLUDES =
StringUtil.split(
SystemProperties.get(
"http.header.secure.x.content.type.options.urls.excludes"));
private static final boolean _X_FRAME_OPTIONS;
private static final String _X_XSS_PROTECTION;
private static final KeyValuePair[] _xFrameOptionKVPs;
static {
String httpHeaderSecureXFrameOptionsKey =
"http.header.secure.x.frame.options";
Properties properties = new SortedProperties(
new Comparator<String>() {
@Override
public int compare(String key1, String key2) {
return GetterUtil.getIntegerStrict(key1) -
GetterUtil.getIntegerStrict(key2);
}
},
PropertiesUtil.getProperties(
SystemProperties.getProperties(),
httpHeaderSecureXFrameOptionsKey.concat(StringPool.PERIOD),
true));
List<KeyValuePair> xFrameOptionKVPs = new ArrayList<>(
properties.size());
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
String propertyValue = (String)entry.getValue();
String[] propertyValueParts = StringUtil.split(
propertyValue, CharPool.PIPE);
if (propertyValueParts.length > 2) {
continue;
}
String url = StringUtil.trim(propertyValueParts[0]);
if (Validator.isNull(url)) {
continue;
}
if (propertyValueParts.length == 1) {
xFrameOptionKVPs.add(new KeyValuePair(url, null));
continue;
}
String value = StringUtil.trim(propertyValueParts[1]);
if (Validator.isNull(value)) {
value = null;
}
xFrameOptionKVPs.add(new KeyValuePair(url, value));
}
_xFrameOptionKVPs = xFrameOptionKVPs.toArray(
new KeyValuePair[xFrameOptionKVPs.size()]);
if (_xFrameOptionKVPs.length == 0) {
_X_FRAME_OPTIONS = false;
}
else {
_X_FRAME_OPTIONS = GetterUtil.getBoolean(
SystemProperties.get(httpHeaderSecureXFrameOptionsKey), true);
}
String xXssProtection = SystemProperties.get(
"http.header.secure.x.xss.protection");
if (Validator.isNull(xXssProtection)) {
_X_XSS_PROTECTION = null;
}
else {
_X_XSS_PROTECTION = xXssProtection;
}
}
}