서블릿 필터를 사용하여 요청 매개 변수 수정
Tomcat 4.1에서 기존 웹 응용 프로그램이 실행되고 있습니다.페이지에 XSS 문제가 있는데 소스를 수정할 수 없습니다.페이지에 파라미터를 표시하기 전에 servlet 필터를 작성하여 삭제하기로 했습니다.
다음과 같은 필터 클래스를 작성하려고 합니다.
import java.io.*;
import javax.servlet.*;
public final class XssFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
String badValue = request.getParameter("dangerousParamName");
String goodValue = sanitize(badValue);
request.setParameter("dangerousParamName", goodValue);
chain.doFilter(request, response);
}
public void destroy() {
}
public void init(FilterConfig filterConfig) {
}
}
★★★★★★★★★★★★★★★★★.ServletRequest.setParameter
존재하지 않습니다.
요청을 체인으로 전달하기 전에 요청 매개 변수 값을 변경하려면 어떻게 해야 합니까?
하신 바와 같이 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」HttpServletRequest
set Parameter를 설정합니다.클래스는 클라이언트로부터의 요구를 나타내므로 이는 의도적인 것이며 파라미터를 변경해도 해당 요구를 나타내지 않습니다.
해결 중 는 '사용하는 방법'을하는 것입니다.HttpServletRequestWrapper
하나를 수 있습니다.class: 떤요요요 、 른른른른른른 。할 수 , 수 있습니다.getParameter
값을 입니다. 포장된 , 하다, 하다, 하다, 하다, 하다에게 하면 됩니다.chain.doFilter
원래 요청 대신.
"servlet API" "서블릿 API" "서브릿 API"에 다른 if른 if if if if if if if if if if if if ifdoFilter
일부 서블릿 컨테이너는 사용자가 사양을 위반했다고 불평하고 처리를 거부합니다.
보다 우아한 솔루션은 더 많은 작업을 수행하는 것입니다. - 원래 서블릿/J를 수정하십시오.SP는 파라미터를 처리하여 파라미터가 아닌 요청 Atribute를 요구합니다.필터는 파라미터를 검사하여 삭제한 후 Atribute를 설정합니다(사용).request.setAttribute
valuesanitized 값 ) ) 。하위 분류나 스푸핑은 없지만 애플리케이션의 다른 부분을 수정해야 합니다.
참고로, 제가 쓰게 된 수업은 다음과 같습니다.
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public final class XssFilter implements Filter {
static class FilteredRequest extends HttpServletRequestWrapper {
/* These are the characters allowed by the Javascript validation */
static String allowedChars = "+-0123456789#*";
public FilteredRequest(ServletRequest request) {
super((HttpServletRequest)request);
}
public String sanitize(String input) {
String result = "";
for (int i = 0; i < input.length(); i++) {
if (allowedChars.indexOf(input.charAt(i)) >= 0) {
result += input.charAt(i);
}
}
return result;
}
public String getParameter(String paramName) {
String value = super.getParameter(paramName);
if ("dangerousParamName".equals(paramName)) {
value = sanitize(value);
}
return value;
}
public String[] getParameterValues(String paramName) {
String values[] = super.getParameterValues(paramName);
if ("dangerousParamName".equals(paramName)) {
for (int index = 0; index < values.length; index++) {
values[index] = sanitize(values[index]);
}
}
return values;
}
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
chain.doFilter(new FilteredRequest(request), response);
}
public void destroy() {
}
public void init(FilterConfig filterConfig) {
}
}
를 를 작성합니다.HttpServletRequestWrapper
된 input.get parameter()의sanitized Parameter합니다..HttpServletRequestWrapper
로로 합니다.Filter.doChain()
직접 요청 오브젝트 대신.
당신의 모든 발언에 근거해, 제 제안은 저에게 효과가 있었습니다.
private final class CustomHttpServletRequest extends HttpServletRequestWrapper {
private final Map<String, String[]> queryParameterMap;
private final Charset requestEncoding;
public CustomHttpServletRequest(HttpServletRequest request) {
super(request);
queryParameterMap = getCommonQueryParamFromLegacy(request.getParameterMap());
String encoding = request.getCharacterEncoding();
requestEncoding = (encoding != null ? Charset.forName(encoding) : StandardCharsets.UTF_8);
}
private final Map<String, String[]> getCommonQueryParamFromLegacy(Map<String, String[]> paramMap) {
Objects.requireNonNull(paramMap);
Map<String, String[]> commonQueryParamMap = new LinkedHashMap<>(paramMap);
commonQueryParamMap.put(CommonQueryParams.PATIENT_ID, new String[] { paramMap.get(LEGACY_PARAM_PATIENT_ID)[0] });
commonQueryParamMap.put(CommonQueryParams.PATIENT_BIRTHDATE, new String[] { paramMap.get(LEGACY_PARAM_PATIENT_BIRTHDATE)[0] });
commonQueryParamMap.put(CommonQueryParams.KEYWORDS, new String[] { paramMap.get(LEGACY_PARAM_STUDYTYPE)[0] });
String lowerDateTime = null;
String upperDateTime = null;
try {
String studyDateTime = new SimpleDateFormat("yyyy-MM-dd").format(new SimpleDateFormat("dd-MM-yyyy").parse(paramMap.get(LEGACY_PARAM_STUDY_DATE_TIME)[0]));
lowerDateTime = studyDateTime + "T23:59:59";
upperDateTime = studyDateTime + "T00:00:00";
} catch (ParseException e) {
LOGGER.error("Can't parse StudyDate from query parameters : {}", e.getLocalizedMessage());
}
commonQueryParamMap.put(CommonQueryParams.LOWER_DATETIME, new String[] { lowerDateTime });
commonQueryParamMap.put(CommonQueryParams.UPPER_DATETIME, new String[] { upperDateTime });
legacyQueryParams.forEach(commonQueryParamMap::remove);
return Collections.unmodifiableMap(commonQueryParamMap);
}
@Override
public String getParameter(String name) {
String[] params = queryParameterMap.get(name);
return params != null ? params[0] : null;
}
@Override
public String[] getParameterValues(String name) {
return queryParameterMap.get(name);
}
@Override
public Map<String, String[]> getParameterMap() {
return queryParameterMap; // unmodifiable to uphold the interface contract.
}
@Override
public Enumeration<String> getParameterNames() {
return Collections.enumeration(queryParameterMap.keySet());
}
@Override
public String getQueryString() {
// @see : https://stackoverflow.com/a/35831692/9869013
// return queryParameterMap.entrySet().stream().flatMap(entry -> Stream.of(entry.getValue()).map(value -> entry.getKey() + "=" + value)).collect(Collectors.joining("&")); // without encoding !!
return queryParameterMap.entrySet().stream().flatMap(entry -> encodeMultiParameter(entry.getKey(), entry.getValue(), requestEncoding)).collect(Collectors.joining("&"));
}
private Stream<String> encodeMultiParameter(String key, String[] values, Charset encoding) {
return Stream.of(values).map(value -> encodeSingleParameter(key, value, encoding));
}
private String encodeSingleParameter(String key, String value, Charset encoding) {
return urlEncode(key, encoding) + "=" + urlEncode(value, encoding);
}
private String urlEncode(String value, Charset encoding) {
try {
return URLEncoder.encode(value, encoding.name());
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("Cannot url encode " + value, e);
}
}
@Override
public ServletInputStream getInputStream() throws IOException {
throw new UnsupportedOperationException("getInputStream() is not implemented in this " + CustomHttpServletRequest.class.getSimpleName() + " wrapper");
}
}
주의: queryString()은 각 KEY의 모든 값을 처리해야 하며 필요에 따라 자체 파라미터 값을 추가할 때 encodeUrl()을 잊지 마십시오.
제한사항으로 request.getParameterMap() 또는 request.getReader()를 호출하여 읽기를 시작하는 메서드를 호출하면 더 이상의 요청 콜을 방지할 수 있습니다.set Character Encoding(...)
같은 문제가 발생했습니다(필터의 HTTP 요청에서 파라미터를 변경).나는 결국 에러가 되었다.ThreadLocal<String>
. 에서에서Filter
하다
class MyFilter extends Filter {
public static final ThreadLocal<String> THREAD_VARIABLE = new ThreadLocal<>();
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
THREAD_VARIABLE.set("myVariableValue");
chain.doFilter(request, response);
}
}
처리기 「 」 「 」 「 」 「 」 ) 。HttpServlet
기타 프로세서) 값이 JSF "HTTP " ) 。
...
String myVariable = MyFilter.THREAD_VARIABLE.get();
...
장점:
- HTTP 매개 변수 전달보다 더 다양한 기능(POJO 개체 전달 가능)
- 약간 고속(변수값을 추출하기 위해 URL을 해석할 필요가 없음)
-
HttpServletRequestWrapper
플레이트 - 요구(HTTP를 실행할 때보다 넓습니다.
request.setAttribute(String,Object)
다른 수
단점:
- 이 메서드는 필터를 처리하는 스레드가 HTTP 요청을 처리하는 스레드와 동일한 경우에만 사용할 수 있습니다(이것은 내가 알고 있는 모든 Java 기반 서버에서 해당).그 결과, 이것은, 다음의 경우에 기능하지 않습니다.
- HTTP 리다이렉트 실행(브라우저가 새로운 HTTP 요구를 실행하고 동일한 스레드로 처리됨을 보증할 수 없기 때문에)
- 개별 스레드로 데이터 처리(예: 사용 시)
java.util.stream.Stream.parallel
,java.util.concurrent.Future
,java.lang.Thread
.
- 요청 프로세서/응용 프로그램을 수정할 수 있어야 합니다.
몇 가지 주의사항:
서버에는 HTTP 요청을 처리하기 위한 스레드 풀이 있습니다.이것은 수영장이기 때문에:
- 의 스레드는 HTTP 요구를 하지만 한 사용 후하거나 각 =해 주십시오).
if (value!=null) { THREAD_VARIABLE.set(value);}
는 "HTTP"가 "HTTP"로 설정되어 있을 때 이전 입니다.value
null null 。부작용이 보증됩니다). - 2개의 요구가 같은 스레드로 처리된다는 보장은 없습니다(그럴 수도 있지만 보증은 없습니다).어떤 요청에서 다른 요청으로 사용자 데이터를 보관해야 하는 경우
- 의 스레드는 HTTP 요구를 하지만 한 사용 후하거나 각 =해 주십시오).
- JEE는 내부적으로
ThreadLocal
단, , 을 합니다.ThreadLocal
이치노JE/CDI 이외의 컨테이너(멀티스레드 JRE 어플리케이션 등)에서도 사용할 수 있습니다.
이게 내가 결국 하게 된 일이야
//import ../../Constants;
public class RequestFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(RequestFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
try {
CustomHttpServletRequest customHttpServletRequest = new CustomHttpServletRequest((HttpServletRequest) servletRequest);
filterChain.doFilter(customHttpServletRequest, servletResponse);
} finally {
//do something here
}
}
@Override
public void destroy() {
}
public static Map<String, String[]> ADMIN_QUERY_PARAMS = new HashMap<String, String[]>() {
{
put("diagnostics", new String[]{"false"});
put("skipCache", new String[]{"false"});
}
};
/*
This is a custom wrapper over the `HttpServletRequestWrapper` which
overrides the various header getter methods and query param getter methods.
Changes to the request pojo are
=> A custom header is added whose value is a unique id
=> Admin query params are set to default values in the url
*/
private class CustomHttpServletRequest extends HttpServletRequestWrapper {
public CustomHttpServletRequest(HttpServletRequest request) {
super(request);
//create custom id (to be returned) when the value for a
//particular header is asked for
internalRequestId = RandomStringUtils.random(10, true, true) + "-local";
}
public String getHeader(String name) {
String value = super.getHeader(name);
if(Strings.isNullOrEmpty(value) && isRequestIdHeaderName(name)) {
value = internalRequestId;
}
return value;
}
private boolean isRequestIdHeaderName(String name) {
return Constants.RID_HEADER.equalsIgnoreCase(name) || Constants.X_REQUEST_ID_HEADER.equalsIgnoreCase(name);
}
public Enumeration<String> getHeaders(String name) {
List<String> values = Collections.list(super.getHeaders(name));
if(values.size()==0 && isRequestIdHeaderName(name)) {
values.add(internalRequestId);
}
return Collections.enumeration(values);
}
public Enumeration<String> getHeaderNames() {
List<String> names = Collections.list(super.getHeaderNames());
names.add(Constants.RID_HEADER);
names.add(Constants.X_REQUEST_ID_HEADER);
return Collections.enumeration(names);
}
public String getParameter(String name) {
if (ADMIN_QUERY_PARAMS.get(name) != null) {
return ADMIN_QUERY_PARAMS.get(name)[0];
}
return super.getParameter(name);
}
public Map<String, String[]> getParameterMap() {
Map<String, String[]> paramsMap = new HashMap<>(super.getParameterMap());
for (String paramName : ADMIN_QUERY_PARAMS.keySet()) {
if (paramsMap.get(paramName) != null) {
paramsMap.put(paramName, ADMIN_QUERY_PARAMS.get(paramName));
}
}
return paramsMap;
}
public String[] getParameterValues(String name) {
if (ADMIN_QUERY_PARAMS.get(name) != null) {
return ADMIN_QUERY_PARAMS.get(name);
}
return super.getParameterValues(name);
}
public String getQueryString() {
Map<String, String[]> map = getParameterMap();
StringBuilder builder = new StringBuilder();
for (String param: map.keySet()) {
for (String value: map.get(param)) {
builder.append(param).append("=").append(value).append("&");
}
}
builder.deleteCharAt(builder.length() - 1);
return builder.toString();
}
}
}
검사에는 정규 표현을 사용할 수 있습니다.chain.doFilter(요구, 응답) 메서드를 호출하기 전에 내부 필터에서 이 코드를 호출합니다.샘플 코드는 다음과 같습니다.
for (Enumeration en = request.getParameterNames(); en.hasMoreElements(); ) {
String name = (String)en.nextElement();
String values[] = request.getParameterValues(name);
int n = values.length;
for(int i=0; i < n; i++) {
values[i] = values[i].replaceAll("[^\\dA-Za-z ]","").replaceAll("\\s+","+").trim();
}
}
해라request.setAttribute("param",value);
나한텐 잘 먹혔어
다음 코드 샘플을 확인하십시오.
private void sanitizePrice(ServletRequest request){
if(request.getParameterValues ("price") != null){
String price[] = request.getParameterValues ("price");
for(int i=0;i<price.length;i++){
price[i] = price[i].replaceAll("[^\\dA-Za-z0-9- ]", "").trim();
System.out.println(price[i]);
}
request.setAttribute("price", price);
//request.getParameter("numOfBooks").re
}
}
언급URL : https://stackoverflow.com/questions/1413129/modify-request-parameter-with-servlet-filter
'programing' 카테고리의 다른 글
CodeIgniter 인증 라이브러리를 선택하려면 어떻게 해야 합니까? (0) | 2022.12.07 |
---|---|
클래스에 동적으로 속성을 추가하려면 어떻게 해야 합니까? (0) | 2022.12.07 |
MySQL과 Maria의 JSON_SEARCH 차이DB (0) | 2022.12.07 |
php 랜덤x 자리수 (0) | 2022.12.07 |
인수를 다른 Javascript 함수로 전달 (0) | 2022.12.07 |