Как защитить от избыточного кодирования пути или параметров запроса?
Вы не можете "защитить от избыточного кодирования". Вы либо кодируете, либо нет. Вы должны всегда знать для любой данной строки, закодирована она или нет. Вы должны кодировать только строки, которые еще не закодированы, и вы никогда не должны кодировать строки, которые уже закодированы.
Так эта строка закодирована или нет?
%3Fref%3Dsomething%26term%3D{keyword}
Мне кажется, что это плохой ввод: очевидно, это не кодированный , потому что он содержит недопустимые символы ('{' и '}'). Тем не менее, она также не является некодированной строкой, поскольку содержит последовательности «% xx». Так что это частично закодировано. Как только строка находится в этой форме, программного решения не существует - вам просто нужно избегать попадания строки в такую форму. Вы можете создать алгоритм, который «исправляет» эту строку, тщательно отыскивая части, похожие на «%», за которыми следуют две шестнадцатеричные цифры, и оставляя их в покое. Но это сломается на тонких случаях. Рассмотрим некодированную строку «42% 23», которая должна быть буквальным представлением математического выражения «42 mod 23». Когда я помещаю это в URI, я ожидаю, что он будет закодирован как «42% 2523», поэтому он будет декодирован как «42% 23», но приведенный выше алгоритм сломается и закодирует его как «42% 23», который затем будет декодирован как « 42 #». Таким образом, нет способа исправить вышеуказанную строку. Кодировка "% 3F" в "% 253F" - это именно то, что должен делать кодировщик URI.
Примечание. Сказав это, браузеры часто позволяют вам вводить плохие символы в URI, и они автоматически их кодируют. Это не очень надежно, поэтому его не следует использовать, если вы не пытаетесь прощать ввод пользователя. В этом случае вы можете сделать «лучшее из возможного», сначала расшифровав URI, а затем перекодировав его. В этом случае, если бы я хотел набрать «42% 23», мне пришлось бы вручную ввести «42% 2523».
Что касается вопроса 2:
Это, однако, приводит к тому, что последний параметр также кодируется
Точно так же, это именно то, что вы хотите. Если URI отображается в качестве параметра внутри другого URI, его значение должно быть в процентах. В противном случае, как вы можете определить, где заканчивается один URI, а другой продолжается? Я полагаю, что приведенный выше URI действительно действителен (поскольку ':', '/', '&' и '=' являются зарезервированными символами, а не запрещены, и поэтому они разрешены, если они не создают неоднозначность). Но гораздо безопаснее избежать использования URI внутри URI.