Servlet响应包装器有编码问题

时间:2011-01-14 23:31:19

标签: java servlets character-encoding wrapper servlet-filters

Servlet响应包装器正在Servlet过滤器中使用。这个想法是响应被操纵,并将“nonce”值注入表单中,作为防御CSRF攻击的一部分。

网络应用程序无处不在使用UTF-8。当Servlet过滤器不存在时,没有问题。添加过滤器时,会出现编码问题。 (似乎响应回复到8859-1。)

代码的内容:

final class CsrfResponseWrapper extends AbstractResponseWrapper {
   ...
   byte[] modifyResponse(byte[] aInputResponse){
      ...
      String originalInput = new String(aInputResponse, encoding);
      String modifiedResult = addHiddenParamToPostedForms(originalInput);
      result = modifiedResult.getBytes(encoding);
      ...
   }
   ...
}

据我了解,byte-land和String-land之间的转换应指定编码。正如你所看到的,这在两个地方就完成了。 'encoding'变量的值是'UTF-8'; String本身的更改是标准字符串操作(使用正则表达式),并且从不指定编码(addHiddenParamToPostedForms)。

我对编码的错误在哪里?

编辑: 这是基类(对不起,它很长):

package hirondelle.web4j.security;

import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;

/**
 Abstract Base Class for altering response content.
 (May be useful in future contexts as well. For now, keep package-private.)  
*/
abstract class AbstractResponseWrapper extends HttpServletResponseWrapper {

  AbstractResponseWrapper(ServletResponse aServletResponse) throws IOException {
    super((HttpServletResponse)aServletResponse);
    fOutputStream = new ModifiedOutputStream(aServletResponse.getOutputStream());
    fWriter = new PrintWriter(fOutputStream);
  }

  /** Return the modified response. */
  abstract byte[] modifyResponse(byte[] aInputResponse);

  /** Standard servlet method.  */
  public final ServletOutputStream getOutputStream() {
    //fLogger.fine("Modified Response : Getting output stream.");
    if ( fWriterReturned ) {
      throw new IllegalStateException();
    }
    fOutputStreamReturned = true;
    return fOutputStream;
  }

  /** Standard servlet method.  */
  public final PrintWriter getWriter() {
    //fLogger.fine("Modified Response : Getting writer.");
    if ( fOutputStreamReturned ) {
      throw new IllegalStateException();
    }
    fWriterReturned = true;
    return fWriter;
  }

  // PRIVATE

  /*
   Well-behaved servlets return either an OutputStream or a PrintWriter, but not both.
  */
  private PrintWriter fWriter; 
  private ModifiedOutputStream fOutputStream;

  /*
   These items are used to implement conformance to the 
   javadoc for ServletResponse, regarding exceptions being thrown.
  */
  private boolean fWriterReturned;
  private boolean fOutputStreamReturned;

  /** Modified low level output stream.  */
  private class ModifiedOutputStream extends ServletOutputStream {
    public ModifiedOutputStream(ServletOutputStream aOutputStream) {
      fServletOutputStream = aOutputStream;
      fBuffer = new ByteArrayOutputStream();
    }
    /** Must be implemented to make this class concrete.   */
    public void write(int aByte) {
      fBuffer.write(aByte);
    }
    public void close() throws IOException {
      if ( !fIsClosed ){
        processStream();
        fServletOutputStream.close();
        fIsClosed = true;
      }
    }
    public void flush() throws IOException {
      if ( fBuffer.size() != 0 ){
        if ( !fIsClosed ) {
          processStream(); 
          fBuffer = new ByteArrayOutputStream();
        }
      }
    }
    /** Perform the core processing, by calling the abstract method.  */
    public void processStream() throws IOException {
      fServletOutputStream.write(modifyResponse(fBuffer.toByteArray()));
      fServletOutputStream.flush();
    }
    // PRIVATE //
    private ServletOutputStream fServletOutputStream;
    private ByteArrayOutputStream fBuffer;
    /** Tracks if this stream has been closed.    */
    private boolean fIsClosed = false;
  }
}

2 个答案:

答案 0 :(得分:5)

来自new PrintWriter(OutputStream) javadoc

  

从现有的OutputStream创建一个没有自动行刷新的新PrintWriter。这个便利构造函数创建了必要的中间OutputStreamWriter,它将使用默认字符编码将字符转换为字节。

这是你的罪魁祸首。请查看OutputStreamWriter,您可以在其中指定编码。

答案 1 :(得分:0)

您提供的代码似乎没有错误。

你在其他地方做什么?

  • 链中是否有其他过滤器可能会操纵编码/字节流,可能是您有过滤器位置问题
  • 是“编码”修复还是动态读取请求?