이것은 의도적으로 설계된 동작입니다. 여기서 일어나는 일은 여러분의 입력이 URI가 두 URI 인코딩과 HTML 엔티티 인코딩을 포함하고 있음을 감지하는 ESAPI의 표준화 된 방법에 의해 잡히고 있다는 것입니다.
ESAPI의 다음 릴리스에는이를위한 편리한 방법이 포함되지만 몇 단계가 필요합니다.
편리한 방법
이
/**
* {@inheritDoc}
*/
public boolean isValidURI(String context, String input, boolean allowNull) {
boolean isValid = false;
URI compliantURI = this.getRfcCompliantURI(input);
try{
if(null != compliantURI){
String canonicalizedURI = getCanonicalizedURI(compliantURI);
//if getCanonicalizedURI doesn't throw an IntrusionException, then the URI contains no mixed or
//double-encoding attacks.
logger.info(Logger.SECURITY_SUCCESS, "We did not detect any mixed or multiple encoding in the uri:[" + input + "]");
Validator v = ESAPI.validator();
//This part will use the regex from validation.properties. This regex should be super-simple, and
//used mainly to restrict certain parts of a URL.
Pattern p = ESAPI.securityConfiguration().getValidationPattern("URL");
//We're doing this instead of using the normal validator API, because it will canonicalize the input again
//and if the URI has any queries that also happen to match HTML entities, like ¶
//it will cease conforming to the regex we now specify for a URL.
isValid = p.matcher(canonicalizedURI).matches();
}
}catch (IntrusionException e){
logger.error(Logger.SECURITY_FAILURE, e.getMessage());
isValid = false;
}
return isValid;
}
/**
* This does alot. This will extract each piece of a URI according to parse zone, and it will construct
* a canonicalized String representing a version of the URI that is safe to run regex against to it.
*
* @param dirtyUri
* @return
* @throws IntrusionException
*/
public String getCanonicalizedURI(URI dirtyUri) throws IntrusionException{
// From RFC-3986 section 3
// URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
//
// hier-part = "//" authority path-abempty
// /path-absolute
// /path-rootless
// /path-empty
// The following are two example URIs and their component parts:
//
// foo://example.com:8042/over/there?name=ferret#nose
// \_/ \______________/\_________/ \_________/ \__/
// | | | | |
// scheme authority path query fragment
// | _____________________|__
// /\/ \
// urn:example:animal:ferret:nose
Map<UriSegment, String> parseMap = new EnumMap<UriSegment, String>(UriSegment.class);
parseMap.put(UriSegment.SCHEME, dirtyUri.getScheme());
//authority = [ userinfo "@" ] host [ ":" port ]
parseMap.put(UriSegment.AUTHORITY, dirtyUri.getRawAuthority());
parseMap.put(UriSegment.SCHEMSPECIFICPART, dirtyUri.getRawSchemeSpecificPart());
parseMap.put(UriSegment.HOST, dirtyUri.getHost());
//if port is undefined, it will return -1
Integer port = new Integer(dirtyUri.getPort());
parseMap.put(UriSegment.PORT, port == -1 ? "": port.toString());
parseMap.put(UriSegment.PATH, dirtyUri.getRawPath());
parseMap.put(UriSegment.QUERY, dirtyUri.getRawQuery());
parseMap.put(UriSegment.FRAGMENT, dirtyUri.getRawFragment());
//Now we canonicalize each part and build our string.
StringBuilder sb = new StringBuilder();
//Replace all the items in the map with canonicalized versions.
Set<UriSegment> set = parseMap.keySet();
SecurityConfiguration sg = ESAPI.securityConfiguration();
// boolean restrictMixed = sg.getBooleanProp("AllowMixedEncoding");
// boolean restrictMultiple = sg.getBooleanProp("AllowMultipleEncoding");
boolean allowMixed = sg.getAllowMixedEncoding();
boolean allowMultiple = sg.getAllowMultipleEncoding();
for(UriSegment seg: set){
String value = encoder.canonicalize(parseMap.get(seg), allowMultiple, allowMixed);
value = value == null ? "" : value;
//In the case of a uri query, we need to break up and canonicalize the internal parts of the query.
if(seg == UriSegment.QUERY && null != parseMap.get(seg)){
StringBuilder qBuilder = new StringBuilder();
try {
Map<String, List<String>> canonicalizedMap = this.splitQuery(dirtyUri);
Set<Entry<String, List<String>>> query = canonicalizedMap.entrySet();
Iterator<Entry<String, List<String>>> i = query.iterator();
while(i.hasNext()){
Entry<String, List<String>> e = i.next();
String key = (String) e.getKey();
String qVal = "";
List<String> list = (List<String>) e.getValue();
if(!list.isEmpty()){
qVal = list.get(0);
}
qBuilder.append(key)
.append("=")
.append(qVal);
if(i.hasNext()){
qBuilder.append("&");
}
}
value = qBuilder.toString();
} catch (UnsupportedEncodingException e) {
logger.debug(Logger.EVENT_FAILURE, "decoding error when parsing [" + dirtyUri.toString() + "]");
}
}
//Check if the port is -1, if it is, omit it from the output.
if(seg == UriSegment.PORT){
if("-1" == parseMap.get(seg)){
value = "";
}
}
parseMap.put(seg, value);
}
return buildUrl(parseMap);
}
/**
* The meat of this method was taken from StackOverflow: http://stackoverflow.com/a/13592567/557153
* It has been modified to return a canonicalized key and value pairing.
*
* @param java URI
* @return a map of canonicalized query parameters.
* @throws UnsupportedEncodingException
*/
public Map<String, List<String>> splitQuery(URI uri) throws UnsupportedEncodingException {
final Map<String, List<String>> query_pairs = new LinkedHashMap<String, List<String>>();
final String[] pairs = uri.getQuery().split("&");
for (String pair : pairs) {
final int idx = pair.indexOf("=");
final String key = idx > 0 ? encoder.canonicalize(pair.substring(0, idx)) : pair;
if (!query_pairs.containsKey(key)) {
query_pairs.put(key, new LinkedList<String>());
}
final String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder.decode(pair.substring(idx + 1), "UTF-8") : null;
query_pairs.get(key).add(encoder.canonicalize(value));
}
return query_pairs;
}
public enum UriSegment {
AUTHORITY, SCHEME, SCHEMSPECIFICPART, USERINFO, HOST, PORT, PATH, QUERY, FRAGMENT
}
참조 코드는
here.을 사는를 정규화 방법이 제대로이 속으로이 부분에서, DefaultEncoder 클래스로 리팩토링됩니다 유의하시기 바랍니다.
작성된 코드는 ESAPI 프로젝트 코드에서 많이 테스트되었지만 한 두 가지 방법을 잊어 버렸을 수 있습니다. 있는 그대로의 esapi 프로젝트를 복제하고 컴파일 할 수 있지만 일부 조직에서는 출혈이 아닌 비 릴리스 바이너리를 사용할 수 없습니다.
고마워, 나는 ESAPI 클래스를 확인하고 똑같은 것을 발견했다. 이제 나는 String에 존재하는 것을 검증 할 새로운 요구 사항을 가지고있다. 그것은 독일어, 프랑스어, 숫자, 특수 문자를 가질 수 있습니다 ... 나는 [. *]와 다른 reg 표현식으로 시도했지만 아무 것도 작동하지 않습니다. 유효한 reg 식을 제안하십시오 – Venkat
@Venkat "SafeString?"에 대한 유효성 검사 호출을 사용하면 어떻게됩니까? – avgvstvs
@Venkat'[. *]'는 아마도 기본적으로 정규 표현식이 ASCII 범위에서만 작동하기 때문에 작동하지 않을 것입니다. 유니 코드 이스케이프를 사용하거나 유니 코드 검사를 켜려면 정규 표현식에'(? u)'를 접두사로 사용해야합니다. – avgvstvs