提交 0be2350d 编写于 作者: M michaelm

6980004: limit HTTP request cookie headers in HttpURLConnection

6961084: limit setting of some request headers in HttpURLConnection
Reviewed-by: chegar
上级 513a4126
...@@ -196,6 +196,10 @@ class MessageHeader { ...@@ -196,6 +196,10 @@ class MessageHeader {
} }
public synchronized Map<String, List<String>> getHeaders(String[] excludeList) { public synchronized Map<String, List<String>> getHeaders(String[] excludeList) {
return filterAndAddHeaders(excludeList, null);
}
public synchronized Map<String, List<String>> filterAndAddHeaders(String[] excludeList, Map<String, List<String>> include) {
boolean skipIt = false; boolean skipIt = false;
Map<String, List<String>> m = new HashMap<String, List<String>>(); Map<String, List<String>> m = new HashMap<String, List<String>>();
for (int i = nkeys; --i >= 0;) { for (int i = nkeys; --i >= 0;) {
...@@ -223,6 +227,19 @@ class MessageHeader { ...@@ -223,6 +227,19 @@ class MessageHeader {
} }
} }
if (include != null) {
Iterator entries = include.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry entry = (Map.Entry)entries.next();
List l = (List)m.get(entry.getKey());
if (l == null) {
l = new ArrayList();
m.put((String)entry.getKey(), l);
}
l.add(entry.getValue());
}
}
for (String key : m.keySet()) { for (String key : m.keySet()) {
m.put(key, Collections.unmodifiableList(m.get(key))); m.put(key, Collections.unmodifiableList(m.get(key)));
} }
......
...@@ -51,6 +51,9 @@ import java.util.List; ...@@ -51,6 +51,9 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.Iterator; import java.util.Iterator;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Set;
import sun.net.*; import sun.net.*;
import sun.net.www.*; import sun.net.www.*;
import sun.net.www.http.HttpClient; import sun.net.www.http.HttpClient;
...@@ -140,6 +143,54 @@ public class HttpURLConnection extends java.net.HttpURLConnection { ...@@ -140,6 +143,54 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
*/ */
private static int bufSize4ES = 0; private static int bufSize4ES = 0;
/*
* Restrict setting of request headers through the public api
* consistent with JavaScript XMLHttpRequest2 with a few
* exceptions. Disallowed headers are silently ignored for
* backwards compatibility reasons rather than throwing a
* SecurityException. For example, some applets set the
* Host header since old JREs did not implement HTTP 1.1.
* Additionally, any header starting with Sec- is
* disallowed.
*
* The following headers are allowed for historical reasons:
*
* Accept-Charset, Accept-Encoding, Cookie, Cookie2, Date,
* Referer, TE, User-Agent, headers beginning with Proxy-.
*
* The following headers are allowed in a limited form:
*
* Connection: close
*
* See http://www.w3.org/TR/XMLHttpRequest2.
*/
private static final boolean allowRestrictedHeaders;
private static final Set<String> restrictedHeaderSet;
private static final String[] restrictedHeaders = {
/* Restricted by XMLHttpRequest2 */
//"Accept-Charset",
//"Accept-Encoding",
"Access-Control-Request-Headers",
"Access-Control-Request-Method",
"Connection", /* close is allowed */
"Content-Length",
//"Cookie",
//"Cookie2",
"Content-Transfer-Encoding",
//"Date",
//"Expect",
"Host",
"Keep-Alive",
"Origin",
// "Referer",
// "TE",
"Trailer",
"Transfer-Encoding",
"Upgrade",
//"User-Agent",
"Via"
};
static { static {
maxRedirects = java.security.AccessController.doPrivileged( maxRedirects = java.security.AccessController.doPrivileged(
new sun.security.action.GetIntegerAction( new sun.security.action.GetIntegerAction(
...@@ -178,7 +229,17 @@ public class HttpURLConnection extends java.net.HttpURLConnection { ...@@ -178,7 +229,17 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
bufSize4ES = 4096; // use the default bufSize4ES = 4096; // use the default
} }
allowRestrictedHeaders = ((Boolean)java.security.AccessController.doPrivileged(
new sun.security.action.GetBooleanAction(
"sun.net.http.allowRestrictedHeaders"))).booleanValue();
if (!allowRestrictedHeaders) {
restrictedHeaderSet = new HashSet<String>(restrictedHeaders.length);
for (int i=0; i < restrictedHeaders.length; i++) {
restrictedHeaderSet.add(restrictedHeaders[i].toLowerCase());
}
} else {
restrictedHeaderSet = null;
}
} }
static final String httpVersion = "HTTP/1.1"; static final String httpVersion = "HTTP/1.1";
...@@ -191,6 +252,15 @@ public class HttpURLConnection extends java.net.HttpURLConnection { ...@@ -191,6 +252,15 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
"Proxy-Authorization", "Proxy-Authorization",
"Authorization" "Authorization"
}; };
// also exclude system cookies when any might be set
private static final String[] EXCLUDE_HEADERS2= {
"Proxy-Authorization",
"Authorization",
"Cookie",
"Cookie2"
};
protected HttpClient http; protected HttpClient http;
protected Handler handler; protected Handler handler;
protected Proxy instProxy; protected Proxy instProxy;
...@@ -213,6 +283,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection { ...@@ -213,6 +283,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
/* User set Cookies */ /* User set Cookies */
private boolean setUserCookies = true; private boolean setUserCookies = true;
private String userCookies = null; private String userCookies = null;
private String userCookies2 = null;
/* We only have a single static authenticator for now. /* We only have a single static authenticator for now.
* REMIND: backwards compatibility with JDK 1.1. Should be * REMIND: backwards compatibility with JDK 1.1. Should be
...@@ -329,6 +400,41 @@ public class HttpURLConnection extends java.net.HttpURLConnection { ...@@ -329,6 +400,41 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
}); });
} }
private boolean isRestrictedHeader(String key, String value) {
if (allowRestrictedHeaders) {
return false;
}
key = key.toLowerCase();
if (restrictedHeaderSet.contains(key)) {
/*
* Exceptions to restricted headers:
*
* Allow "Connection: close".
*/
if (key.equals("connection") && value.equalsIgnoreCase("close")) {
return false;
}
return true;
} else if (key.startsWith("sec-")) {
return true;
}
return false;
}
/*
* Checks the validity of http message header and whether the header
* is restricted and throws IllegalArgumentException if invalid or
* restricted.
*/
private boolean isExternalMessageHeaderAllowed(String key, String value) {
checkMessageHeader(key, value);
if (!isRestrictedHeader(key, value)) {
return true;
}
return false;
}
/* Logging support */ /* Logging support */
public static PlatformLogger getHttpLogger() { public static PlatformLogger getHttpLogger() {
return logger; return logger;
...@@ -1047,15 +1153,21 @@ public class HttpURLConnection extends java.net.HttpURLConnection { ...@@ -1047,15 +1153,21 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
// we only want to capture the user defined Cookies once, as // we only want to capture the user defined Cookies once, as
// they cannot be changed by user code after we are connected, // they cannot be changed by user code after we are connected,
// only internally. // only internally.
if (setUserCookies) { synchronized (this) {
int k = requests.getKey("Cookie"); if (setUserCookies) {
if ( k != -1) int k = requests.getKey("Cookie");
userCookies = requests.getValue(k); if ( k != -1)
setUserCookies = false; userCookies = requests.getValue(k);
k = requests.getKey("Cookie2");
if ( k != -1)
userCookies2 = requests.getValue(k);
setUserCookies = false;
}
} }
// remove old Cookie header before setting new one. // remove old Cookie header before setting new one.
requests.remove("Cookie"); requests.remove("Cookie");
requests.remove("Cookie2");
URI uri = ParseUtil.toURI(url); URI uri = ParseUtil.toURI(url);
if (uri != null) { if (uri != null) {
...@@ -1101,6 +1213,13 @@ public class HttpURLConnection extends java.net.HttpURLConnection { ...@@ -1101,6 +1213,13 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
else else
requests.set("Cookie", userCookies); requests.set("Cookie", userCookies);
} }
if (userCookies2 != null) {
int k;
if ((k = requests.getKey("Cookie")) != -1)
requests.set("Cookie2", requests.getValue(k) + ";" + userCookies2);
else
requests.set("Cookie2", userCookies2);
}
} // end of getting cookies } // end of getting cookies
} }
...@@ -2539,8 +2658,9 @@ public class HttpURLConnection extends java.net.HttpURLConnection { ...@@ -2539,8 +2658,9 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
if (key == null) if (key == null)
throw new NullPointerException ("key is null"); throw new NullPointerException ("key is null");
checkMessageHeader(key, value); if (isExternalMessageHeaderAllowed(key, value)) {
requests.set(key, value); requests.set(key, value);
}
} }
/** /**
...@@ -2561,8 +2681,9 @@ public class HttpURLConnection extends java.net.HttpURLConnection { ...@@ -2561,8 +2681,9 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
if (key == null) if (key == null)
throw new NullPointerException ("key is null"); throw new NullPointerException ("key is null");
checkMessageHeader(key, value); if (isExternalMessageHeaderAllowed(key, value)) {
requests.add(key, value); requests.add(key, value);
}
} }
// //
...@@ -2575,13 +2696,23 @@ public class HttpURLConnection extends java.net.HttpURLConnection { ...@@ -2575,13 +2696,23 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
} }
@Override @Override
public String getRequestProperty (String key) { public synchronized String getRequestProperty (String key) {
if (key == null) {
return null;
}
// don't return headers containing security sensitive information // don't return headers containing security sensitive information
if (key != null) { for (int i=0; i < EXCLUDE_HEADERS.length; i++) {
for (int i=0; i < EXCLUDE_HEADERS.length; i++) { if (key.equalsIgnoreCase(EXCLUDE_HEADERS[i])) {
if (key.equalsIgnoreCase(EXCLUDE_HEADERS[i])) { return null;
return null; }
} }
if (!setUserCookies) {
if (key.equalsIgnoreCase("Cookie")) {
return userCookies;
}
if (key.equalsIgnoreCase("Cookie2")) {
return userCookies2;
} }
} }
return requests.findValue(key); return requests.findValue(key);
...@@ -2600,12 +2731,29 @@ public class HttpURLConnection extends java.net.HttpURLConnection { ...@@ -2600,12 +2731,29 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
* @since 1.4 * @since 1.4
*/ */
@Override @Override
public Map<String, List<String>> getRequestProperties() { public synchronized Map<String, List<String>> getRequestProperties() {
if (connected) if (connected)
throw new IllegalStateException("Already connected"); throw new IllegalStateException("Already connected");
// exclude headers containing security-sensitive info // exclude headers containing security-sensitive info
return requests.getHeaders(EXCLUDE_HEADERS); if (setUserCookies) {
return requests.getHeaders(EXCLUDE_HEADERS);
}
/*
* The cookies in the requests message headers may have
* been modified. Use the saved user cookies instead.
*/
Map userCookiesMap = null;
if (userCookies != null || userCookies2 != null) {
userCookiesMap = new HashMap();
if (userCookies != null) {
userCookiesMap.put("Cookie", userCookies);
}
if (userCookies2 != null) {
userCookiesMap.put("Cookie2", userCookies2);
}
}
return requests.filterAndAddHeaders(EXCLUDE_HEADERS2, userCookiesMap);
} }
@Override @Override
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册