При использовании URI
String myUri = "https://evil.example.com\\.good.example.org/";
// or
String myUri = "https://evil.example.com\\@good.example.org/";
в Java на Android обратная косая черта в информации о хосте или пользователе в авторитетной части URI вызывает несоответствие между тем, как android.net.Uri и android.webkit.WebView Android анализируют URI относительно своего хоста.
Uri (и cURL) обрабатывает evil.example.com\.good.example.org (первый пример) или даже good.example.org (второй пример) как хост URI.WebView (а также Firefox и Chrome) обрабатывает evil.example.com (оба примера) как хост URI.Это известное, ожидаемое или правильное поведение? Следуют ли два класса просто разным стандартам?
Глядя на спецификацию, кажется, что ни RFC 2396, ни RFC 3986 не допускают обратной косой черты в информации или полномочиях пользователя.
Есть ли обходной путь для обеспечения согласованного поведения здесь, особенно для целей проверки? Разумно ли выглядит следующий патч (для использования с WebView и для общей корректности)?
Uri myParsedUri = Uri.parse(myUri);
if ((myParsedUri.getHost() == null || !myParsedUri.getHost().contains("\\")) && (myParsedUri.getUserInfo() == null || !myParsedUri.getUserInfo().contains("\\"))) {
// valid URI
}
else {
// invalid URI
}
Один из возможных недостатков заключается в том, что этот обходной путь может не уловить все случаи, которые вызывают анализ несогласованных хостов. Знаете ли вы что-нибудь еще (кроме обратной косой черты), которое вызывает несоответствие между двумя классами?
Известно, что Android WebView 4.4 конвертирует некоторые URL, в связанной проблеме описаны некоторые шаги, как предотвратить это. Из вашего вопроса не совсем понятно, основана ли ваша потребность на этом или чем-то другом.
Вы можете замаскировать обратную косую черту и другие знаки с помощью соответствующего номера в таблице символов. В URL-адресах номер записывается в шестнадцатеричном формате.
Hexadecimal: 5C
Dezimal: 92
Sign: \
К коду добавляется % для каждого знака в URL-адресе, ваш код после замены выглядит следующим образом:
String myUri = "https://evil.example.com%5C%5C.good.example.org/";
// or
String myUri = "https://evil.example.com%5C%[email protected]/";
может потребоваться добавить косую черту для разделения домена и пути:
String myUri = "https://evil.example.com/%5C%5C.good.example.org/";
// or
String myUri = "https://evil.example.com/%5C%[email protected]/";
Возможно ли, что обратная косая черта никогда не будет использоваться для сетевого взаимодействия, а будет служить в качестве экранирования для некоторых процедур, таких как регулярные выражения, или для вывода в JavaScript (Json) или некоторых других шагов?
Бонус ;-)
Ниже приведен php-скрипт, который печатает таблицу для большинства знаков UTF-8 с соответствующими числами в шестнадцатеричном и десятичном формате. (он все еще должен быть завернут в html-шаблон, включая, возможно, css):
<?php
$chs = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
$chs2 = $chs;
$chs3 = $chs;
$chs4 = $chs;
foreach ($chs as $ch){
foreach ($chs2 as $ch2){
foreach ($chs3 as $ch3){
foreach ($chs4 as $ch4){
echo '<tr>';
echo '<td>';
echo $ch.$ch2.$ch3.$ch4;
echo '</td>';
echo '<td>';
echo hexdec($ch.$ch2.$ch3.$ch4);
echo '</td>';
echo '<td>';
echo '&#x'.$ch.$ch2.$ch3.$ch4.';';
echo '</td>';
echo '</tr>';
}
}
}
}
?>
извините, я никогда не читал достаточно внимательно ваше заявление, касающееся RFC. Я исправил эту часть. В остальном, я думаю, это действительно будет зависеть от специальной настройки сервера. Может быть, вы все еще можете обрисовать особый вариант использования, мне непонятно, почему он вообще должен быть желательным или обязательным
@caw, все же добавил (жирный) вопрос в свой ответ
Речь идет не об изменениях в Android 4.4. Это не имеет отношения к данному вопросу. Такое же поведение можно воспроизвести на Android 5 или более поздней версии. Вопрос также не в каком-то особом случае использования, а в различии в поведении между классом WebView (и, следовательно, реализацией Chrome, поддерживающей эти экземпляры WebView) и классом Uri. Это все. Если вам нужен вариант использования: злоумышленник может предоставить вам вредоносные URL-адреса, например с помощью Intent, если вы позволяете это, или с помощью созданных URL-адресов, если ваше приложение настроено на открытие определенных шаблонов URL-адресов. Вы можете определить здесь хост URL.
Вопрос в том, зачем нужны эти URL внутри классов или почему они так построены. Итак, мой вопрос был больше связан с внутренней структурой классов или со специальным сервером, который позволяет использовать обратную косую черту по особой причине (например, в Google Play). Также единственный вариант использования для объединения двух URL-адресов - это некоторые веб-службы, такие как поисковые запросы (например, whois), реферер в качестве параметра или сходство. но тогда используется маскирование или только чистый домен без использования косой черты. Поскольку я не использую ни android.net, ни android-webview, проблема может показаться мне немного странной.
Is this known, expected or correct behavior?
ИМО, это не так. И для URI, и для WebView. Поскольку RFC не допускает обратной косой черты, они могли бы предупредить об этом. Однако это менее важно, потому что это не влияет на работу вообще, если вход ожидал.
Do the two classes simply follow different standards?
Классы URI и WebView строго следуют одним и тем же стандартам. Но из-за того, что это разные реализации, они могут вести себя по-разному по отношению к входу непредвиденный.
Например, "^(([^:/?#]+):)?((//([^/?#]*))?([^?#]*)(\\?([^#]*))?)?(#(.*))?" - это регулярное выражение в URI, которое используется для анализа URI. Разбор URI WebView выполняется собственными методами CPP. Несмотря на то, что они следуют одним и тем же стандартам, у них есть шансы дать другой результат (по крайней мере, для неожиданных исходных данных).
Does the following patch look reasonable?
Не совсем (см. Ответ на следующий вопрос).
Do you know of anything else (apart from a backslash) that causes a mismatch between the two classes?
Поскольку вас так беспокоит согласованное поведение, я не буду предлагать ручную проверку. Даже программисты, написавшие эти классы, не могут перечислить все такие сценарии.
Если я правильно понимаю, вам нужно загрузить URL-адреса, которые предоставляются ненадежными внешними источниками (которые злоумышленники могут использовать, если есть лазейка), но вам необходимо правильно идентифицировать его хост.
В этом случае вы можете проанализировать его, используя сам класс URI, и использовать URI#getHost() для идентификации хоста. Но для WebView вместо передачи исходной строки URL-адреса передайте URI#toString().
Спасибо! Я бы не согласился и сказал, что обратная косая черта в значительной степени является вводом ожидал - точнее говоря, она ожидаема и недействительна. Оба класса должны пройти проверку и потерпеть неудачу. Очевидно, никто из нас не может ничего изменить в этом. Что касается WebView, они, похоже, просто выбрали то, что делают большинство автономных браузеров, то есть переписывают ввод вместо того, чтобы терпеть неудачу при проверке. Для Uri, похоже, это сделано из соображений производительности, как сказано в документации. Таким образом, можно понять, почему они решили не проверять, но тогда у разработчика должен быть способ проверки.
Я всегда делал парсинг URL и вызов getHost на этом экземпляре. В этом весь смысл этого вопроса: результат этого метода getHost не согласуется с тем, что делает WebView, поэтому он бесполезен и необходимо что-то еще. Кстати, похоже, вы объединили android.net.Uri и java.net.URI. Первый - вот о чем этот вопрос. Последнее - это то, что вы можете иметь в виду, постоянно записывая URI.
Ваше решение использовать Uri.parse(myUri).toString() или new URI(myUri).toString() вместо просто myUri и передать его в WebView вообще не работает. Первый просто возвращает то же значение и поэтому бесполезен. Последний ничего не возвращает, но терпит неудачу с java.net.URISyntaxException: Illegal character in authority - что хорошо, но не то, что указано в вашем решении, и не класс, о котором этот вопрос был.
Спасибо, но вопрос вовсе не в том, как правильно кодировать обратную косую черту (для чего просто требуется хорошо известное процентное кодирование), а как исправить проверку URL-адресов, содержащих обратную косую черту в Java на Android. Кроме того, я сделал нет, чтобы сказать, что некоторые RFC позволяют буквально использовать обратную косую черту. Вместо этого я сказал, что ни один из двух соответствующих RFC допускает это.