リクエスト入力フローの取得

23672 ワード

文書ディレクトリ
  • 前言
  • POST要求の入力フローを取得し、
  • を修正する.
  • まとめ
  • 前言
    私たちはリクエストをブロックするときによくこのような問題に遭遇します.私たちはブロックfilterでrequestのリクエストを取得したいと思っています.リクエストのデフォルトのgetInputStream()メソッドやgetReader()メソッドを使用してデータを取得しますが、後のControllerで@ResquestBody注釈を使用してrequestのbodyの値が読めません.これはrequestのbodyのデータはgetInputStream()とgetReader()メソッドで1回しか読み取れないため、この問題を解決するにはrequestリクエストを書き換えるgetInputStream()とgetReader()メソッドを使用します.
    POST要求の入力フローを取得し、修正する
    一般的にPOSTリクエストで私たちが持っている情報はアプリケーション/json形式です.いくつかのシナリオでは、これらのPOSTリクエストのアプリケーション/json情報を取得、解析します.まずコードを見てください.
    public class XssRequestWrapper extends HttpServletRequestWrapper {
    
        private static Policy policy = null;
    
        private static final AntiSamy antiSamy = new AntiSamy();
        /**
         *   Body  String  
         */
        private String body;
        /**
         * application/json   Map  
         */
        private Map<String, String> parameters = new HashMap<String, String>();
        /**
         *      
         */
        private byte[] bytes;
        /**
         *              
         */
        private boolean isInit = false;
        /**
         *         
         */
        private static final String DEFAULT_CHARSET_NAME = "UTF-8";
        private ObjectMapper objectMapper = new ObjectMapper();
    
        public XssRequestWrapper(HttpServletRequest request) throws IOException {
            super(request);
            try {
                String contentType = request.getContentType();
                if(contentType.contains(";")){
                    contentType = contentType.substring(0,contentType.indexOf(";"));
                }
                //   bytes    
                initBytes();
                //  application/json    
                if(contentType.equals(MediaType.APPLICATION_JSON_VALUE)){
                    parseJsonParameters();
                }
            } catch (IOException e) {
                throw new RuntimeException("IOException", e);
            }
        }
        /**
         *               
         * @throws IOException
         */
        private void initBytes() throws IOException {
            isInit = true;
            StringBuilder buffer = new StringBuilder();
            BufferedReader reader = this.getHttpServletRequest().getReader();
            String line;
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            body = buffer.toString();
            //        
            bytes = body.getBytes(DEFAULT_CHARSET_NAME);
        }
        /**
         *   ApplicationJson  ,    XSS  
         * @throws IOException
         */
        private void parseJsonParameters() throws IOException {
            StringBuilder stringBuilder = new StringBuilder("{");
            if (null != body && body.length() > 0) {
                JsonNode node = objectMapper.readTree(body);
                Iterator<String> fieldNames = node.getFieldNames();
                for (; fieldNames.hasNext();) {
                    String key = fieldNames.next();
                    String value = node.get(key).toString();
                    if (value.length() > 2 && value.startsWith("\"")) {
                        String valueTemp = value.substring(1,value.length()-1);
                        valueTemp = StringEscapeUtils.unescapeJava(valueTemp);
                        //TODO:XSS     
                       
                        valueTemp = StringEscapeUtils.escapeJava(valueTemp);
                        valueTemp = "\"" + valueTemp + "\"";
                        parameters.put(key, valueTemp);
                    } else {
                        parameters.put(key, value);
                    }
                }
            }
            for(String key:parameters.keySet()){
                String value = parameters.get(key);
                stringBuilder.append("\""+key+"\":"+value+",");
            }
            stringBuilder.deleteCharAt(stringBuilder.length()-1);
            stringBuilder.append("}");
            try {
                bytes = stringBuilder.toString().getBytes(DEFAULT_CHARSET_NAME);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        private HttpServletRequest getHttpServletRequest() {
            return (HttpServletRequest) super.getRequest();
        }
        /**
         *   getReader  
         * @return
         * @throws IOException
         */
        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(getInputStream()));
        }
        /**
         *   getInputStream()  
         *     body  
         * @return
         * @throws IOException
         */
        @Override
        public ServletInputStream getInputStream() throws IOException {
            if (!isInit)
                initBytes();
            final ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
    
            return new ServletInputStream() {
                @Override
                public int read() throws IOException {
                    return bais.read();
                }
            };
        }
    

    まとめ
    分析:Post要求入力フローを取得し、データが失われないことを保証する手順は以下の通りです.
  • 親の構築方法を継承し、独自の方法でデータの初期化
  • を行う.
  • データの初期化は,入力ストリームを取得し,本クラスのchar[]bytesに
  • を書き込むことである.
  • 再getInputStream()メソッドとgetReader()メソッドで、getInputStream()メソッドはbytesバイトストリーム情報
  • を直接読み出す
  • アプリケーション/jsonデータを解析し、JsonNodeクラス
  • を利用する