2012-12-11 1 views
2

У меня есть форма, где у меня есть текстовое поле и кнопка отправки. Я использую инструмент burp, чтобы изменить значение, представленное в форме, для проверки моей проверки на стороне сервера.UTF-8 | выпуск со специальным символом на форме submit | java.io.CharConversionException

Проверка на стороне сервера работает нормально, если только нет знака %, введенного из инструмента burp, при вводе % символов на сервере отображается следующее исключение.

2012-12-11 11:37:07,860 WARN [org.apache.tomcat.util.http.Parameters] (ajp-0.0.0.0-8109-19) Parameters: Character decoding failed. Parameter skipped. 
java.io.CharConversionException: EOF 
       at org.apache.tomcat.util.buf.UDecoder.convert(UDecoder.java:83) 
       at org.apache.tomcat.util.buf.UDecoder.convert(UDecoder.java:49) 
       at org.apache.tomcat.util.http.Parameters.urlDecode(Parameters.java:429) 
       at org.apache.tomcat.util.http.Parameters.processParameters(Parameters.java:412) 
       at org.apache.tomcat.util.http.Parameters.processParameters(Parameters.java:363) 
       at org.apache.catalina.connector.Request.parseParameters(Request.java:2562) 
       at org.apache.catalina.connector.Request.getParameter(Request.java:1060) 
       at org.apache.catalina.connector.RequestFacade.getParameter(RequestFacade.java:355) 
       at org.displaytag.filter.ResponseOverrideFilter.doFilter(ResponseOverrideFilter.java:118) 
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) 
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
       at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:235) 
       at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) 
       at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:190) 
       at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92) 
       at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126) 
       at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70) 
       at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) 
       at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) 
       at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158) 
       at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) 
       at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330) 
       at org.apache.coyote.ajp.AjpProcessor.process(AjpProcessor.java:436) 
       at org.apache.coyote.ajp.AjpProtocol$AjpConnectionHandler.process(AjpProtocol.java:384) 
       at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447) 
       at java.lang.Thread.run(Thread.java:662) 

, когда я отправить форму с символом%, она меняет его% 25 правильно, но как я справиться с этим на стороне сервера?

+0

с помощью winshark, чтобы получить данные чтения клиента представить. – andy

ответ

0

Другие ответы правильны при рассмотрении Безопасно попросить вас, чтобы закодировать ваш вклад, так как все браузеры будут делать так, как хорошо, и вы в идеале никогда не получит символ без кодировки %.

Но, если вы все еще настаиваете на том, чтобы увидеть страницу с ошибкой; можно написать собственный фильтр, чтобы поймать этот CharConversionException и отправить клиенту страницу с ошибкой или перенаправить запрос в тот же URI, но с набором атрибутов , чтобы запрос обрабатывался по-разному.

Это настраивается здесь с помощью параметра фильтра с именем useErrorPage.

EDIT: В свете исходного кода разделяемого @Santosh, который показывает, что CharConversionException фактически подавляются с помощью Tomcat я изменил фильтр впрыснуть проверку параметров и проверить все параметры запроса для списка запрещенных символов, может быть сконфигурирован с помощью параметра фильтра с именем forbiddenChars.

Поместите этот фильтр над ResponseAverrideFilter DisplayTag в файл web.xml, чтобы убедиться, что он перехватывает все. Заказ может иметь свои побочные эффекты, когда дело касается фильтров.

Я бы это изменение как возможность, чтобы подчеркнуть тот факт, что Фильтры сервлета это очень мощная концепция, которая позволяет до или после процесса любой запрос в любом случае вы хотите. Большинство веб-фреймворков (например, Struts 2 для MVC) используют фильтры, чтобы служить их точками входа.

Итак, есть очень мало, что вы не можете сделать с фильтрами. Просто убедитесь, что вы используете их для правильной цели, так как бизнес-логика, очевидно, не должна идти туда, хотя проверка подлинности на основе приложений может быть решена.

IOException Фильтр

public class CharConversionExpFilter implements Filter { 

    private char[] forbiddenChars; // ADDED 
    private FilterConfig filterConfig; 

    @Override 
    public void init(FilterConfig filterConfig) throws ServletException { 
     this.filterConfig = filterConfig; 
     forbiddenChars = filterConfig.getInitParameter("forbiddenChars") 
           .replace(",", "").toCharArray(); // ADDED 
    } 

    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, 
      FilterChain chain) throws IOException, ServletException { 
     String requestURI = ((HttpServletRequest) request).getRequestURI(); 
     try { 
      validateParameters((HttpServletRequest) request); // ADDED 
      chain.doFilter(request, response); 
     } catch (IOException e) { 
      if (e instanceof CharConversionException) { 
       if ("true".equalsIgnoreCase(filterConfig.getInitParameter("useErrorPage"))) { 
        if (response instanceof HttpServletResponse) { 
         ((HttpServletResponse) response).sendError(400, 
         "The request cannot be fulfilled due to bad input.\nError:" + e.getMessage()); 
        } 
       } else { 
        request.setAttribute("errorMessage", e.getMessage()); 
        filterConfig.getServletContext().getRequestDispatcher(requestURI).forward(request, response); 
       } 
      } 
     } 
    } 

    // ADDED 
    private void validateParameters(HttpServletRequest request) throws CharConversionException { 
     Enumeration<String> parameterNames = request.getParameterNames(); 
     while (parameterNames.hasMoreElements()) { 
      String parameter = request.getParameter(parameterNames.nextElement()); 
      if (parameter != null && parameter.length() > 0) { 
       for (char forbidChar : forbiddenChars) { 
        if (parameter.indexOf(forbidChar) != -1) { 
         throw new CharConversionException(
           String.format(
             "Parameter: [%s] contains the forbidden character [%c]", 
             parameter, forbidChar)); 
        } 
       } 
      } 
     } 
    } 

    @Override 
    public void destroy() {} 
} 


веб.XML

<filter> 
    <filter-name>CharConversionExpFilter</filter-name> 
    <filter-class>servlet.filter.CharConversionExpFilter</filter-class> 
    <init-param> 
    <param-name>useErrorPage</param-name> 
    <param-value>true</param-value> 
    </init-param> 
    <init-param> <!-- ADDED --> 
    <param-name>forbiddenChars</param-name> 
    <param-value>%,*,?,#,$</param-value> <!-- filtering wildcards and EL chars --> 
    </init-param> 
</filter> 

<filter-mapping> 
    <filter-name>CharConversionExpFilter</filter-name> 
    <url-pattern>/*</url-pattern> <!-- * = ALL; "/servlet-name" if required --> 
</filter-mapping> 

<error-page> 
    <error-code>400</error-code> 
    <location>/errorPage.jsp</location> <!-- isErrorPage = true; use "exception" obj --> 
</error-page> 


Надеюсь, что это дает вам достаточно указателей, чтобы выработать решение в соответствии с вашими потребностями. (Примечание:. Подсветка синтаксиса интерпретирует <url-pattern>/* неправильно как начало многострочного Java комментария Пожалуйста, игнорируйте это.)

+0

Вы попробовали это? Я пробовал то же самое, но фильтры do.filter() никогда не попадают в исключение, а параметр (значение которого передается как%) имеет значение NULL. Это исключение, которое бросается и съедается, никогда не размножается. – Santosh

+0

@ Сантош Хорошая находка! Я предположил, что общая стекловата пришла из-за того, что выбрано исключение. Я изменил фильтр, чтобы в настоящее время ввести проверку и пресекать эту проблему в бутоне. –

+0

Приятное обходное решение, но IMO это исключение никогда не предназначалось для обработки и, что еще важнее, указывает на проблему ** нарушения протокола http ** в инструменте, который отправляет запрос. Потенциально, может быть еще много проблем с нарушением протокола (ошибки в инструменте), и с ними будет сложно справиться. – Santosh

1

Проблема, с которой вы столкнулись, заключается в том, что декодер ожидает действительный, декодируемый параметр, когда он начинается с символа %. При отправке формы входной параметр % правильно кодируется в %25, когда вы редактируете этот запрос с помощью Burp, эта кодировка не выполняется, насколько я знаю. Burp охотно отправляет вашему серверу символ %, и ваша проверка на стороне сервера предполагает, что это начало закодированного значения, но при этом не происходит какого-либо декодирования, потому что его, ну, в принципе, является сломанным параметром.

Мое лучшее предположение заключается не в том, чтобы отправлять только% -значения (то есть без сопровождающего числа). Это похоже на вызов метода с нулевой ссылкой. Некоторые вещи просто не работают. Я бы сказал, что вы пытаетесь проверить, одобряется или отклоняется процентный символ с помощью вашей собственной проверки ввода, но пока он проходит через декодирование, он должен быть закодирован.

+0

Я могу понять, что вы говорите, но мне нужен способ, благодаря которому я мог поймать это исключение и показать пользователю пользовательскую страницу ошибок. Как видно, это исключение генерируется в некоторой библиотеке tomcat, я не могу это сделать. – Ankit

+0

К сожалению, у меня нет дальнейших идей для этого. Может быть, какой-то перехватчик может заполучить запрос до того, как расшифровка url начнется? Я сомневаюсь, что хотя .. – Scorpio

0

С этим тестом (в том числе необработанным «%» в том, что должно быть URL-кодированными данными), вы проверяете, что ваше приложение соответствующим образом отклоняет неверный ввод. В этом нет ничего плохого.

Если вы хотите нажимать данные с помощью отрыжка, вам нужно закодировать его, то есть вам нужно ввести «% 25», где вы хотите «%».

0

Если вы внимательно изучаете трассировку стека, все классы, участвующие в анализе HTTP-текста в объект запроса Java, находятся из фреймворка и не контролируют пользователя.

Теперь основная предпосылка за это: Сервер всегда будет считать, что данные, которые он получил, всегда URL закодирован и, следовательно, она всегда будет пытаться расшифровать.

Если декодирование завершается неудачно, это означает, что основные принципы протокола HTTP не были соблюдены и, следовательно, полностью отбрасывают запрос, не давая пользователю возможности обработать его.

Так что ИМХО, вы не можете справиться с этим условием, поскольку сервер правильно обрабатывает его сам по себе.

EDIT:

Одно решение, предложенное @Ravi выше выглядит как она решает эту проблему. Я пробовал один и тот же код, но я никогда не мог поймать исключение!

Копаем глубже, стало ясно, почему это исключение (java.io.CharConversionException) невозможно обработать в любом пользовательском коде.

Хотя java.io.CharConversionException выбрасывается, но его никогда не распространяют в иерархии вызовов.Вот почему,

В трассировке стека

 at org.apache.tomcat.util.buf.UDecoder.convert(UDecoder.java:83) 
     at org.apache.tomcat.util.buf.UDecoder.convert(UDecoder.java:49) 
     at org.apache.tomcat.util.http.Parameters.urlDecode(Parameters.java:429) 
     at org.apache.tomcat.util.http.Parameters.processParameters(Parameters.java:412) 

Посмотрите на источник метода processParameters() в классе org.apache.tomcat.util.http.Parameters (код взят из grepcode)

public void processParameters(byte bytes[], int start, int len, 
            String enc) { 
     int end=start+len; 
     int pos=start; 

     if(debug>0) 
      log("Bytes: " + new String(bytes, start, len)); 

     do { 
      boolean noEq=false; 
      int valStart=-1; 
      int valEnd=-1; 

      int nameStart=pos; 
      int nameEnd=ByteChunk.indexOf(bytes, nameStart, end, '='); 
      // Workaround for a&b&c encoding 
      int nameEnd2=ByteChunk.indexOf(bytes, nameStart, end, '&'); 
      if((nameEnd2!=-1) && 
       (nameEnd==-1 || nameEnd > nameEnd2)) { 
       nameEnd=nameEnd2; 
       noEq=true; 
       valStart=nameEnd; 
       valEnd=nameEnd; 
       if(debug>0) log("no equal " + nameStart + " " + nameEnd + " " + new String(bytes, nameStart, nameEnd-nameStart)); 
      } 
      if(nameEnd== -1) 
       nameEnd=end; 

      if(! noEq) { 
       valStart= (nameEnd < end) ? nameEnd+1 : end; 
       valEnd=ByteChunk.indexOf(bytes, valStart, end, '&'); 
       if(valEnd== -1) valEnd = (valStart < end) ? end : valStart; 
      } 

      pos=valEnd+1; 

      if(nameEnd<=nameStart) { 
       log.warn("Parameters: Invalid chunk ignored."); 
       continue; 
       // invalid chunk - it's better to ignore 
      } 
      tmpName.setBytes(bytes, nameStart, nameEnd-nameStart); 
      tmpValue.setBytes(bytes, valStart, valEnd-valStart); 

      try { 
       addParam(urlDecode(tmpName, enc), urlDecode(tmpValue, enc)); 
      } catch (IOException e) { 
       // Exception during character decoding: skip parameter 
       log.warn("Parameters: Character decoding failed. " + 
         "Parameter skipped.", e); 
      } 

      tmpName.recycle(); 
      tmpValue.recycle(); 

     } while(pos<end); 
    } 

В методе есть цикл do-while для анализа всех параметров запроса. Посмотрите на блок try-catch в конце цикла в методе. Существует комментарий, который говорит

// Exception during character decoding: skip parameter 

Таким образом, даже если исключение, но его не распространяется. Он зарегистрирован как предупреждающее сообщение и значение параметра равно null. Так что ясно, что вы никогда не будете в состоянии поймать это исключение (java.io.CharConversionException)

+0

Как показал Рави, пользователь может контролировать это через сервлет-фильтры. –

+0

Это не работает. См. Мое редактирование. Надеюсь, вы пересмотряте свой нисходящий сигнал. – Santosh

+0

@OldPro, если у вас есть downvoted, пожалуйста, пересмотреть его. Я дал достаточно доказательств в своем ответе. – Santosh